1 /* @source embshow ************************************************************
2 **
3 ** General routines for sequence display.
4 **
5 ** @author Copyright (c) 2000 Gary Williams
6 ** @version $Revision: 1.52 $
7 ** @modified $Date: 2013/06/29 22:39:26 $ by $Author: rice $
8 ** @@
9 **
10 ** This library is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU Lesser General Public
12 ** License as published by the Free Software Foundation; either
13 ** version 2.1 of the License, or (at your option) any later version.
14 **
15 ** This library is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 ** Lesser General Public License for more details.
19 **
20 ** You should have received a copy of the GNU Lesser General Public
21 ** License along with this library; if not, write to the Free Software
22 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 ** MA  02110-1301,  USA.
24 ******************************************************************************/
25 
26 
27 #include "ajlib.h"
28 
29 #include "embshow.h"
30 #include "embprop.h"
31 #include "embmat.h"
32 #include "ajlist.h"
33 #include "ajseq.h"
34 #include "ajfeat.h"
35 #include "ajrange.h"
36 #include "ajtranslate.h"
37 
38 #include <ctype.h>
39 
40 
41 
42 /*
43 **
44 ** TO ADD A NEW DISPLAY TYPE:
45 **
46 **
47 **
48 ** Example: complement of the sequence
49 **
50 ** Create a new type in the descriptor object types 'enum ShowEValtype'.
51 ** eg: SH_COMP
52 ** Use this to refer to this type in later routines. (eg: by embShowAddComp)
53 **
54 ** Create a structure to hold information about what options for this type
55 ** you can have.
56 ** eg: typedef struct EmbSShowComp { ... }
57 **
58 ** Create a function called by the user to set up the new type as the next
59 ** thing to be displayed in the list of things.
60 ** eg: embShowAddComp
61 **
62 ** Create the routine to actually output a line's length of whatever is
63 ** being displayed from position 'pos' of the sequence - the output is
64 ** added to the end of a list of AjPStr.
65 ** Everything to be printed should be ajListPushAppend'd on to the 'lines' list.
66 ** These strings need not be complete lines - you can push many strings of
67 ** partial lines if you prefer.
68 ** End the lines to be output by pushing a string ending with a '\n'.
69 ** As many lines as you wish may be pushed onto the lines list.
70 ** eg: showFillComp
71 **
72 ** Add a case statement to showFillLines to call the showFill* routine.
73 ** eg:
74 **      case SH_COMP:
75 **      showFillComp(this, lines, info, pos);
76 **      break;
77 **
78 ** Changes needed:
79 ** Sorting of ranges for translation
80 **
81 ** Translation of entire sequence range and then division of the
82 ** resulting sequence into reading frames. Needed so that translation
83 ** across the joins gives the correct residue. This may involve some
84 ** changes to the timing of conversion from 1 letter to 3 letter code.
85 **
86 */
87 
88 
89 
90 
91 static void    showFillRE(const EmbPShow thys, AjPList lines,
92 			  EmbPShowRE info, ajuint pos,ajuint last);
93 static void    showFillREflat(const EmbPShow thys,
94 			      AjPList lines, const EmbPShowRE info,
95 			      ajuint pos,ajuint last);
96 static void    showFillREupright(const EmbPShow thys, AjPList lines,
97 				 EmbPShowRE info, ajuint pos,ajuint last);
98 static ajint   showFillREuprightSort(const void* a, const void* b);
99 static void    showOverPrint(AjPStr *target, ajint start, AjPStr insert);
100 static AjBool  showLineIsClear(AjPStr *line, ajint start, ajint end);
101 static void    showFillLines(AjPList lines, const EmbPShow thys,
102 			     ajuint pos, ajuint last);
103 static void    showPrintLines(AjPFile out, const AjPList lines);
104 static void    showMargin(const EmbPShow thys, AjPList lines);
105 static void    showMarginNumber(const EmbPShow thys,
106 				AjPList lines, ajint number);
107 static void    showPad(AjPList lines, ajint number);
108 static void    showInsertHTML(AjPStr *target, ajuint pos, const AjPStr insert);
109 
110 static void    showFillSeq(const EmbPShow thys,
111 			   AjPList lines, const EmbPShowSeq info,
112 			   ajuint pos,ajuint last);
113 static void    showFillBlank(const EmbPShow thys,
114 			     AjPList lines, const EmbPShowBlank info,
115 			     ajuint pos,ajuint last);
116 static void    showFillTicks(const EmbPShow thys,
117 			     AjPList lines, const EmbPShowTicks info,
118 			     ajuint pos,ajuint last);
119 static void    showFillTicknum(const EmbPShow thys, AjPList lines,
120 			       const EmbPShowTicknum info,
121 			       ajuint pos,ajuint last);
122 static void    showFillComp(const EmbPShow thys,
123 			    AjPList lines, const EmbPShowComp info,
124 			    ajuint pos,ajuint last);
125 static void    showFillTran(const EmbPShow thys,
126 			    AjPList lines, EmbPShowTran info,
127 			    ajuint pos,ajuint last);
128 static void    showFillFT(const EmbPShow thys,
129 			  AjPList lines, const EmbPShowFT info,
130 			  ajuint pos,ajuint last);
131 static void    showFillNote(const EmbPShow thys,
132 			    AjPList lines, const EmbPShowNote info,
133 			    ajuint pos,ajuint last);
134 
135 static void showDelSeq(EmbPShowSeq* pinfo);
136 static void showDelBlank(EmbPShowBlank* pinfo);
137 static void showDelTicks(EmbPShowTicks* pinfo);
138 static void showDelTicknum(EmbPShowTicknum* pinfo);
139 static void showDelComp(EmbPShowComp* pinfo);
140 static void showDelTran(EmbPShowTran* pinfo);
141 static void showDelRE(EmbPShowRE* pinfo);
142 static void showDelFT(EmbPShowFT* pinfo);
143 static void showDelNote(EmbPShowNote* pinfo);
144 static void showAddTags(AjPStr *tagsout, const AjPFeature feat, AjBool values);
145 
146 
147 
148 /* ==================================================================== */
149 /* ========================= constructors ============================= */
150 /* ==================================================================== */
151 
152 
153 
154 
155 /* @section Show Sequence Constructors ****************************************
156 **
157 ** All constructors return a new show sequence object by pointer.
158 ** The target pointer does not need to be initialised to NULL, but it is
159 ** good programming practice to do so anyway.
160 **
161 ******************************************************************************/
162 
163 
164 
165 
166 /* @func embShowNew ***********************************************************
167 **
168 ** Creates a new sequence show object.
169 **
170 ** @param [r] seq [const AjPSeq] Sequence to describe
171 ** @param [r] begin [ajint] start position in  sequence
172 ** @param [r] end [ajint] end position in  sequence
173 ** @param [r] width [ajint] width of displayed sequence on a line
174 ** @param [r] length [ajint] length of a page in lines (0=no length)
175 ** @param [r] margin [ajint] margin for numbers etc.
176 ** @param [r] html [AjBool] format output for HTML
177 ** @param [r] offset [ajint] number to start display of position numbering at
178 ** @return [EmbPShow] New sequence show object.
179 **
180 ** @release 1.0.0
181 ** @@
182 ******************************************************************************/
183 
embShowNew(const AjPSeq seq,ajint begin,ajint end,ajint width,ajint length,ajint margin,AjBool html,ajint offset)184 EmbPShow embShowNew(const AjPSeq seq, ajint begin, ajint end, ajint width,
185 		    ajint length, ajint margin, AjBool html, ajint offset)
186 {
187     EmbPShow pthis;
188 
189     AJNEW0(pthis);
190 
191     pthis->list = ajListNew();
192 
193     /* information about the sequence */
194     pthis->seq     = seq;
195     pthis->nucleic = ajSeqIsNuc(seq); /* ajTrue = sequence is nucleic */
196     pthis->start   = begin;
197     pthis->end     = end;
198 
199     /* information about the page layout */
200     pthis->width  = width;	     /* length of sequence per line */
201     pthis->length = length;    	     /* length of a page (0 = indefinite) */
202     pthis->margin = margin;	     /* margin for numbering */
203     pthis->html   = html;	     /* ajTrue = format for HTML */
204     pthis->offset = offset;	     /* number to start displaying with */
205 
206     return pthis;
207 }
208 
209 
210 
211 
212 /* @funcstatic showInfoNew ****************************************************
213 **
214 ** Creates a new descriptor structure to be pushed on the list
215 **
216 ** @param [r] info [void*] descriptor
217 ** @param [r] type [ajint] type of descriptor
218 ** @return [EmbPShowInfo] New sequence show object.
219 **
220 ** @release 1.0.0
221 ** @@
222 ******************************************************************************/
223 
showInfoNew(void * info,ajint type)224 static EmbPShowInfo showInfoNew(void* info, ajint type)
225 {
226     EmbPShowInfo pthis;
227 
228     AJNEW0(pthis);
229 
230     pthis->info = info;
231     pthis->type = type;
232 
233     return pthis;
234 }
235 
236 
237 
238 
239 /* ==================================================================== */
240 /* ========================== destructors ============================= */
241 /* ==================================================================== */
242 
243 
244 
245 
246 /* @section Show Sequence Destructors *****************************************
247 **
248 ** Destruction destroys all internal data structures and frees the
249 ** memory allocated for the show sequence object.
250 **
251 ******************************************************************************/
252 
253 
254 
255 
256 /* @func embShowDel ***********************************************************
257 **
258 ** Deletes a show sequence object.
259 **
260 ** @param [d] pthis [EmbPShow*] Show sequence object
261 ** @return [void]
262 **
263 ** @release 1.0.0
264 ** @@
265 ******************************************************************************/
266 
embShowDel(EmbPShow * pthis)267 void embShowDel(EmbPShow* pthis)
268 {
269     EmbPShow thys;
270     AjIList iter;
271     EmbPShowInfo infostruct;
272     ajint type;				/* descriptor type */
273     void *ptr = NULL;
274 
275     ajDebug("embShowDel\n");
276 
277     /*****  DO NOT: ajSeqDel(&pthis->seq); *****/
278 
279     thys = *pthis;
280 
281     /* free the descriptors */
282     iter = ajListIterNewread(thys->list);
283 
284     while((infostruct = ajListIterGet(iter)) != NULL)
285     {
286 
287 	/* iterate through the descriptors filling out the lines */
288 	type = infostruct->type;
289 
290 	switch(type)
291 	{
292             case SH_SEQ:
293                 showDelSeq((EmbPShowSeq*) &infostruct->info);
294                 break;
295 
296             case SH_BLANK:
297                 showDelBlank((EmbPShowBlank*) &infostruct->info);
298                 break;
299 
300             case SH_TICK:
301                 showDelTicks((EmbPShowTicks*) &infostruct->info);
302                 break;
303 
304             case SH_TICKNUM:
305                 showDelTicknum((EmbPShowTicknum*) &infostruct->info);
306                 break;
307 
308             case SH_COMP:
309                 showDelComp((EmbPShowComp*) &infostruct->info);
310                 break;
311 
312             case SH_TRAN:
313                 showDelTran((EmbPShowTran*) &infostruct->info);
314                 break;
315 
316             case SH_RE:
317                 showDelRE((EmbPShowRE*) &infostruct->info);
318                 break;
319 
320             case SH_FT:
321                 showDelFT((EmbPShowFT*) &infostruct->info);
322                 break;
323 
324             case SH_NOTE:
325                 showDelNote((EmbPShowNote*) &infostruct->info);
326                 break;
327 
328             default:
329                 ajFatal("Unknown descriptor type found in embShowDel: %d",
330                         type);
331 	}
332 
333 
334 	AJFREE(infostruct);
335     }
336 
337     ajListIterDel(&iter);
338 
339     /* we have already freed the descriptors, so use ajListFree here */
340     while(ajListPop(thys->list,(void **)&ptr));
341     ajListFree(&thys->list);
342 
343     AJFREE(*pthis);
344 
345     return;
346 }
347 
348 
349 
350 
351 /* @funcstatic showDelSeq *****************************************************
352 **
353 ** Deletes a show sequence descriptor object.
354 **
355 ** @param [d] pinfo [EmbPShowSeq*] Show sequence descriptor object
356 ** @return [void]
357 **
358 ** @release 1.0.0
359 ** @@
360 ******************************************************************************/
361 
showDelSeq(EmbPShowSeq * pinfo)362 static void showDelSeq(EmbPShowSeq* pinfo)
363 {
364     AJFREE(*pinfo);
365 
366     return;
367 }
368 
369 
370 
371 
372 /* @funcstatic showDelBlank ***************************************************
373 **
374 ** Deletes a show blank descriptor object.
375 **
376 ** @param [d] pinfo [EmbPShowBlank*] Show blank descriptor object
377 ** @return [void]
378 **
379 ** @release 1.0.0
380 ** @@
381 ******************************************************************************/
382 
showDelBlank(EmbPShowBlank * pinfo)383 static void showDelBlank(EmbPShowBlank* pinfo)
384 {
385     AJFREE(*pinfo);
386 
387     return;
388 }
389 
390 
391 
392 
393 /* @funcstatic showDelTicks ***************************************************
394 **
395 ** Deletes a show ticks descriptor object.
396 **
397 ** @param [d] pinfo [EmbPShowTicks*] Show ticks descriptor object
398 ** @return [void]
399 **
400 ** @release 1.0.0
401 ** @@
402 ******************************************************************************/
403 
showDelTicks(EmbPShowTicks * pinfo)404 static void showDelTicks(EmbPShowTicks* pinfo)
405 {
406     AJFREE(*pinfo);
407 
408     return;
409 }
410 
411 
412 
413 
414 /* @funcstatic showDelTicknum *************************************************
415 **
416 ** Deletes a show tick numbers descriptor object.
417 **
418 ** @param [d] pinfo [EmbPShowTicknum*] Show tick numbers descriptor object
419 ** @return [void]
420 **
421 ** @release 1.0.0
422 ** @@
423 ******************************************************************************/
424 
showDelTicknum(EmbPShowTicknum * pinfo)425 static void showDelTicknum(EmbPShowTicknum* pinfo)
426 {
427     AJFREE(*pinfo);
428 
429     return;
430 }
431 
432 
433 
434 
435 /* @funcstatic showDelComp ****************************************************
436 **
437 ** Deletes a show complement descriptor object.
438 **
439 ** @param [d] pinfo [EmbPShowComp*] Show complement descriptor object
440 ** @return [void]
441 **
442 ** @release 1.0.0
443 ** @@
444 ******************************************************************************/
445 
showDelComp(EmbPShowComp * pinfo)446 static void showDelComp(EmbPShowComp* pinfo)
447 {
448     AJFREE(*pinfo);
449 
450     return;
451 }
452 
453 
454 
455 
456 /* @funcstatic showDelTran ****************************************************
457 **
458 ** Deletes a show translation descriptor object.
459 **
460 ** @param [d] pinfo [EmbPShowTran*] Show translation descriptor object
461 ** @return [void]
462 **
463 ** @release 1.0.0
464 ** @@
465 ******************************************************************************/
466 
showDelTran(EmbPShowTran * pinfo)467 static void showDelTran(EmbPShowTran* pinfo)
468 {
469     EmbPShowTran info;
470 
471     info = *pinfo;
472 
473     /* AJB: Why was the seqdel commented out? Memory leak without it */
474     ajSeqDel(&info->transeq);
475     AJFREE(*pinfo);
476 
477     return;
478 }
479 
480 
481 
482 
483 /* @funcstatic showDelRE ******************************************************
484 **
485 ** Deletes a show restriction enzyme descriptor object.
486 **
487 ** @param [d] pinfo [EmbPShowRE*] Show restriction enzyme descriptor object
488 ** @return [void]
489 **
490 ** @release 1.0.0
491 ** @@
492 ******************************************************************************/
493 
showDelRE(EmbPShowRE * pinfo)494 static void showDelRE(EmbPShowRE* pinfo)
495 {
496     void *ptr;
497     EmbPShowRE info;
498 
499     info = *pinfo;
500 
501     ajListFree(&info->matches);		/* the nodes are elsewhere */
502 
503     while(ajListPop(info->sitelist,(void **)&ptr))
504 	AJFREE(ptr);
505 
506     ajListFree(&info->sitelist);
507 
508     AJFREE(*pinfo);
509 
510     return;
511 }
512 
513 
514 
515 
516 /* @funcstatic showDelFT ******************************************************
517 **
518 ** Deletes a show feature table descriptor object.
519 **
520 ** @param [d] pinfo [EmbPShowFT*] Show feature table descriptor object
521 ** @return [void]
522 **
523 ** @release 1.0.0
524 ** @@
525 ******************************************************************************/
526 
showDelFT(EmbPShowFT * pinfo)527 static void showDelFT(EmbPShowFT* pinfo)
528 {
529     EmbPShowFT info;
530 
531     info = *pinfo;
532 
533     ajFeattableDel(&info->feat);   /* cloned pointer in showseq etc.*/
534     AJFREE(*pinfo);
535 
536     return;
537 }
538 
539 
540 
541 
542 /* @funcstatic showDelNote ****************************************************
543 **
544 ** Deletes a show annotation region descriptor object.
545 **
546 ** @param [d] pinfo [EmbPShowNote*] Show annotation region descriptor object
547 ** @return [void]
548 **
549 ** @release 2.1.0
550 ** @@
551 ******************************************************************************/
552 
showDelNote(EmbPShowNote * pinfo)553 static void showDelNote(EmbPShowNote* pinfo)
554 {
555     AJFREE(*pinfo);
556 
557     return;
558 }
559 
560 
561 
562 
563 /* ==================================================================== */
564 /* ========================== Assignments ============================= */
565 /* ==================================================================== */
566 
567 
568 
569 
570 /* @section Show Sequence Assignments *****************************************
571 **
572 ** These functions add to the show sequence object provided as the
573 ** first argument.
574 **
575 ******************************************************************************/
576 
577 
578 
579 
580 /* @func embShowAddSeq ********************************************************
581 **
582 ** Adds the sequence to be displayed to the list of things to show
583 ** This must be done before the final printing is done as without a sequence
584 ** to hang all the other features and things on, there can be no output to
585 ** show.
586 **
587 ** @param [u] thys [EmbPShow] Show sequence object
588 ** @param [r] number [AjBool] Number the sequence
589 ** @param [r] threeletter [AjBool] Use three letter protein code
590 ** @param [r] upperrange [const AjPRange] Range of sequence to uppercase
591 ** @param [r] colour [const AjPRange] Range of sequence to colour in HTML
592 ** @return [void]
593 **
594 ** @release 1.0.0
595 ** @@
596 ******************************************************************************/
597 
embShowAddSeq(EmbPShow thys,AjBool number,AjBool threeletter,const AjPRange upperrange,const AjPRange colour)598 void embShowAddSeq(EmbPShow thys, AjBool number, AjBool threeletter,
599 		   const AjPRange upperrange, const AjPRange colour)
600 {
601     EmbPShowSeq info;
602 
603     AJNEW0(info);
604 
605     info->number      = number;
606     info->threeletter = threeletter; /* use three-letter protein code */
607     info->upperrange  = upperrange;  /* Range of sequence to uppercase */
608     info->highlight   = colour;	     /* Range to colour in HTML */
609 
610     ajListPushAppend(thys->list, showInfoNew(info, SH_SEQ));
611 
612     return;
613 }
614 
615 
616 
617 
618 /* @func embShowAddBlank ******************************************************
619 **
620 ** Adds a blank line to the list of things to show.
621 **
622 ** @param [u] thys [EmbPShow] Show sequence object
623 ** @return [void]
624 **
625 ** @release 1.0.0
626 ** @@
627 ******************************************************************************/
628 
embShowAddBlank(EmbPShow thys)629 void embShowAddBlank(EmbPShow thys)
630 {
631     EmbPShowBlank info;
632 
633     ajDebug("embShowAddBlank\n");
634 
635     AJNEW0(info);
636 
637     ajListPushAppend(thys->list, showInfoNew(info, SH_BLANK));
638 
639     return;
640 }
641 
642 
643 
644 
645 /* @func embShowAddTicks ******************************************************
646 **
647 ** Adds a ticks line to the list of things to show.
648 **
649 ** @param [u] thys [EmbPShow] Show sequence object
650 ** @return [void]
651 **
652 ** @release 1.0.0
653 ** @@
654 ******************************************************************************/
655 
embShowAddTicks(EmbPShow thys)656 void embShowAddTicks(EmbPShow thys)
657 {
658 
659     EmbPShowTicks info;
660 
661     ajDebug("embShowAddTicks\n");
662 
663     AJNEW0(info);
664 
665     ajListPushAppend(thys->list, showInfoNew(info, SH_TICK));
666 
667     return;
668 }
669 
670 
671 
672 
673 /* @func embShowAddTicknum ****************************************************
674 **
675 ** Adds a ticks number line to the list of things to show.
676 **
677 ** @param [u] thys [EmbPShow] Show sequence object
678 ** @return [void]
679 **
680 ** @release 1.0.0
681 ** @@
682 ******************************************************************************/
683 
embShowAddTicknum(EmbPShow thys)684 void embShowAddTicknum(EmbPShow thys)
685 {
686     EmbPShowTicknum info;
687 
688     ajDebug("embShowAddTicknum\n");
689 
690     AJNEW0(info);
691 
692     ajListPushAppend(thys->list, showInfoNew(info, SH_TICKNUM));
693 
694     return;
695 }
696 
697 
698 
699 
700 /* @func embShowAddComp *******************************************************
701 **
702 ** Adds the sequence complement to be displayed to the list of things to show
703 **
704 ** @param [u] thys [EmbPShow] Show sequence object
705 ** @param [r] number [AjBool] ajTrue = number the complement
706 ** @return [void]
707 **
708 ** @release 1.0.0
709 ** @@
710 ******************************************************************************/
711 
embShowAddComp(EmbPShow thys,AjBool number)712 void embShowAddComp(EmbPShow thys, AjBool number)
713 {
714     EmbPShowComp info;
715 
716     ajDebug("embShowAddComp\n");
717 
718     AJNEW0(info);
719 
720     info->number = number;
721 
722     ajListPushAppend(thys->list, showInfoNew(info, SH_COMP));
723 
724     return;
725 }
726 
727 
728 
729 
730 /* @func embShowAddTran *******************************************************
731 **
732 ** Adds the translation to be displayed to the list of things to show
733 **
734 ** @param [u] thys [EmbPShow] Show sequence object
735 ** @param [r] trnTable [const AjPTrn] Translation table
736 ** @param [r] frame [ajint] Reading frame to translate
737 ** @param [r] threeletter [AjBool] ajTrue for 3 letter code
738 ** @param [r] number [AjBool] ajTrue for numbering
739 ** @param [r] regions [const AjPRange] Sequence range(s)
740 ** @param [r] orfminsize [ajint] Minimum length of ORF to be shown
741 ** @param [r] lcinterorf [AjBool] ajTrue to put inter-orf regions in lowercase
742 ** @param [r] firstorf [AjBool] ajTrue beginning of the seq is a possible ORF
743 ** @param [r] lastorf [AjBool] ajTrue end of the seq is a possible ORF
744 ** @param [r] showframe [AjBool] ajTrue write the frame number
745 ** @return [void]
746 **
747 ** @release 1.0.0
748 ** @@
749 ******************************************************************************/
750 
embShowAddTran(EmbPShow thys,const AjPTrn trnTable,ajint frame,AjBool threeletter,AjBool number,const AjPRange regions,ajint orfminsize,AjBool lcinterorf,AjBool firstorf,AjBool lastorf,AjBool showframe)751 void embShowAddTran(EmbPShow thys, const AjPTrn trnTable, ajint frame,
752 		    AjBool threeletter, AjBool number, const AjPRange regions,
753 		    ajint orfminsize, AjBool lcinterorf, AjBool firstorf,
754 		    AjBool lastorf, AjBool showframe)
755 {
756     EmbPShowTran info;
757 
758     ajDebug("embShowAddTran\n");
759 
760     AJNEW0(info);
761 
762     info->trnTable = trnTable;		/* translation table */
763     info->frame    = frame;             /* 1,2,3,-1,-2 or -3 = frame to
764 					   translate */
765     info->threeletter = threeletter;    /* ajTrue = display in 3 letter code */
766     info->regions     = regions;        /* only translate these regions,
767 					   NULL = all */
768     info->number = number;	        /* ajTrue = number the translation */
769     info->orfminsize = orfminsize;      /* minimum size of ORF to display */
770 
771     /* these are used by showFillTran */
772     info->transeq = NULL;               /* not yet stored the translation
773 					   here */
774     info->tranpos = 0;	                /* store translation position for
775 					   numbering */
776     info->lcinterorf = lcinterorf;      /* ajTrue = put the inter-orf regions
777 					   in lower case */
778     info->firstorf  = firstorf;
779     info->lastorf   = lastorf;
780     info->showframe = showframe;
781 
782     ajListPushAppend(thys->list, showInfoNew(info, SH_TRAN));
783 
784     return;
785 }
786 
787 
788 
789 
790 /* @func embShowAddRE *********************************************************
791 **
792 ** Adds the Restriction Enzymes to be displayed to the list of things to show
793 **
794 ** @param [u] thys [EmbPShow] Show sequence object
795 ** @param [r] sense [ajint] sense to translate (+1 or -1)
796 ** @param [r] restrictlist [const AjPList] restriction enzyme cut site list
797 ** @param [r] plasmid [AjBool] Circular (plasmid) sequence
798 ** @param [r] flat [AjBool] show in flat format with recognition sites
799 ** @return [void]
800 **
801 ** @release 1.0.0
802 ** @@
803 ******************************************************************************/
804 
embShowAddRE(EmbPShow thys,ajint sense,const AjPList restrictlist,AjBool plasmid,AjBool flat)805 void embShowAddRE(EmbPShow thys, ajint sense, const AjPList restrictlist,
806 		  AjBool plasmid, AjBool flat)
807 {
808     EmbPShowRE info;
809     ajDebug("embShowAddRE\n");
810 
811     AJNEW0(info);
812 
813     info->sense = sense;		/* 1 or -1 = sense to translate */
814     info->flat = flat;		        /* upright or flat display */
815     info->hits = (ajuint) ajListGetLength(restrictlist);
816     info->matches = ajListNewListref(restrictlist);
817     info->sitelist = NULL;	        /* show we have not yet created this
818 					   list */
819     info->plasmid = plasmid;
820 
821     ajListPushAppend(thys->list, showInfoNew(info, SH_RE));
822 
823     return;
824 }
825 
826 
827 
828 
829 /* @func embShowAddFT *********************************************************
830 **
831 ** Adds the Features to be displayed to the list of things to show
832 **
833 ** @param [u] thys [EmbPShow] Show sequence object
834 ** @param [r] feat [const AjPFeattable] features
835 ** @return [void]
836 **
837 ** @release 1.0.0
838 ** @@
839 ******************************************************************************/
840 
embShowAddFT(EmbPShow thys,const AjPFeattable feat)841 void embShowAddFT(EmbPShow thys, const AjPFeattable feat)
842 {
843     EmbPShowFT info;
844 
845     ajDebug("embShowAddFT\n");
846 
847     AJNEW0(info);
848 
849     info->feat = ajFeattableNewFtable(feat); /* store the feature table */
850 
851     ajListPushAppend(thys->list, showInfoNew(info, SH_FT));
852 
853     return;
854 }
855 
856 
857 
858 
859 /* @func embShowAddNote *******************************************************
860 **
861 ** Adds the annotations to be displayed to the list of things to show
862 **
863 ** @param [u] thys [EmbPShow] Show sequence object
864 ** @param [r] regions [const AjPRange] Sequence range(s)
865 ** @return [void]
866 **
867 ** @release 2.1.0
868 ** @@
869 ******************************************************************************/
870 
embShowAddNote(EmbPShow thys,const AjPRange regions)871 void embShowAddNote(EmbPShow thys, const AjPRange regions)
872 {
873     EmbPShowNote info;
874     ajDebug("embShowAddNote\n");
875 
876     AJNEW0(info);
877 
878     info->regions = regions;		/* regions to note */
879 
880     ajListPushAppend(thys->list, showInfoNew(info, SH_NOTE));
881 
882     return;
883 }
884 
885 
886 
887 
888 /* ==================================================================== */
889 /* =========================== Modifiers ============================== */
890 /* ==================================================================== */
891 
892 
893 
894 
895 /* @section Show Sequence Modifiers *******************************************
896 **
897 ** These functions modify the behaviour of the last show descriptor on
898 ** the list.
899 **
900 **
901 ******************************************************************************/
902 
903 
904 
905 
906 
907 
908 /* ==================================================================== */
909 /* ======================== Operators ==================================*/
910 /* ==================================================================== */
911 
912 
913 
914 
915 /* @section Show Sequence Operators *******************************************
916 **
917 ** These functions use the contents of a Show object but do not modify it.
918 **
919 ******************************************************************************/
920 
921 
922 
923 
924 /* @func embShowPrint *********************************************************
925 **
926 ** Prints a Show object
927 **
928 ** @param [u] out [AjPFile] Output file handle
929 ** @param [r] thys [const EmbPShow] Show sequence object
930 ** @return [void]
931 **
932 ** @release 1.0.0
933 ** @@
934 ******************************************************************************/
935 
embShowPrint(AjPFile out,const EmbPShow thys)936 void embShowPrint(AjPFile out, const EmbPShow thys)
937 {
938     AjPList lines;		    /* list of lines to be printed */
939     ajuint pos;		            /* current printing position in sequence */
940     ajuint start;
941     ajuint end;
942     AjIList liter;		    /* iterator for lines */
943     AjPStr line;
944     ajuint count   = 0;		    /* count of newlines in the list */
945     ajuint line_no = 0;		    /* line number on page */
946     ajuint last = 0;
947 
948     ajDebug("embShowPrint start:%u end:%u\n", thys->start, thys->end);
949 
950     /* set up the start and end positions to print */
951     start = thys->start;
952     end = thys->end;
953     last = start-1;
954 
955     /* run through the whole sequence, line-width by line-width */
956     for(pos = start; pos<=end; pos += thys->width)
957     {
958 	last += thys->width;
959 
960 	if(last >= end)
961 	    last = end;
962 
963 	/* make a new list of lines */
964 	lines=ajListstrNew();
965 	/* put the sequence and any other descriptors in the lines list */
966 	showFillLines(lines, thys, pos, last);
967 
968 	/* throw a formfeed if we would go over the length of the page */
969 	count = 0;
970 	liter = ajListIterNewread(lines);
971 
972 	while((line = ajListIterGet(liter)) != NULL)
973 	    if(ajStrGetLen(line))
974 		if(ajStrGetPtr(line)[ajStrGetLen(line)-1] == '\n')
975 		    count++;
976 	ajListIterDel(&liter);
977 
978 	/* thys->length is zero if we have an indefinite page length */
979 	if(thys->length && (count+line_no > thys->length) &&
980 	   (count < thys->length))
981 	{
982 	    line_no = 0;
983 	    ajFmtPrintF(out, "%c", '\f'); /* form feed character */
984 	}
985 
986 	showPrintLines(out, lines);
987 	ajListstrFreeData(&lines);
988     }
989 
990     return;
991 }
992 
993 
994 
995 
996 /* @funcstatic showPrintLines *************************************************
997 **
998 ** Print the lines to the output.
999 **
1000 ** @param [u] out [AjPFile] Output file handle
1001 ** @param [r] lines [const AjPList] lines to print
1002 ** @return [void]
1003 **
1004 ** @release 1.0.0
1005 ** @@
1006 ******************************************************************************/
1007 
showPrintLines(AjPFile out,const AjPList lines)1008 static void showPrintLines(AjPFile out, const AjPList lines)
1009 {
1010     AjIList liter;			/* iterator for lines */
1011     AjPStr str;
1012 
1013     ajDebug("showPrintLines\n");
1014 
1015     /* iterate through the lines and print them */
1016     liter = ajListIterNewread(lines);
1017 
1018     while((str = ajListIterGet(liter)) != NULL)
1019 	ajFmtPrintF(out, "%S", str);
1020 
1021     ajListIterDel(&liter);
1022 
1023     return;
1024 }
1025 
1026 
1027 
1028 
1029 /* ==================================================================== */
1030 /* ======================== Assignments ================================*/
1031 /* ==================================================================== */
1032 
1033 
1034 
1035 
1036 /* @section Show Fill Assignments *********************************************
1037 **
1038 ** These functions fill out the sequence and features lines according to the
1039 ** descriptor data.
1040 **
1041 ******************************************************************************/
1042 
1043 
1044 
1045 
1046 /* @funcstatic showFillLines **************************************************
1047 **
1048 ** Calls the descriptor routines to fill the lines.
1049 **
1050 ** @param [u] lines [AjPList] Lines list
1051 ** @param [r] thys [const EmbPShow] Show sequence object
1052 ** @param [r] pos [ajuint] position in sequence so far while printing
1053 ** @param [r] last [ajuint] final position in sequence so far while printing
1054 ** @return [void]
1055 **
1056 ** @release 1.0.0
1057 ** @@
1058 ******************************************************************************/
1059 
showFillLines(AjPList lines,const EmbPShow thys,ajuint pos,ajuint last)1060 static void showFillLines(AjPList lines, const EmbPShow thys,
1061 			  ajuint pos, ajuint last)
1062 {
1063     EmbPShowInfo infostruct;		/* structure of type and descriptor */
1064     ajint type;				/* descriptor type */
1065     void * info;			/* descriptor */
1066 
1067     AjIList diter;			/* iterator for descriptors */
1068 
1069     ajDebug("showFillLines\n");
1070 
1071     /* iterate through the descriptors filling out the lines */
1072     diter = ajListIterNewread(thys->list);
1073 
1074     while((infostruct = ajListIterGet(diter)) != NULL)
1075     {
1076 	type = infostruct->type;
1077 	info = infostruct->info;
1078 
1079 	switch(type)
1080 	{
1081             case SH_SEQ:
1082                 showFillSeq(thys, lines, info, pos, last);
1083                 break;
1084 
1085             case SH_BLANK:
1086                 showFillBlank(thys, lines, info, pos, last);
1087                 break;
1088 
1089             case SH_TICK:
1090                 showFillTicks(thys, lines, info, pos, last);
1091                 break;
1092 
1093             case SH_TICKNUM:
1094                 showFillTicknum(thys, lines, info, pos, last);
1095                 break;
1096 
1097             case SH_COMP:
1098                 showFillComp(thys, lines, info, pos, last);
1099                 break;
1100 
1101             case SH_TRAN:
1102                 showFillTran(thys, lines, info, pos, last);
1103                 break;
1104 
1105             case SH_RE:
1106                 showFillRE(thys, lines, info, pos, last);
1107                 break;
1108 
1109             case SH_FT:
1110                 showFillFT(thys, lines, info, pos, last);
1111                 break;
1112 
1113             case SH_NOTE:
1114                 showFillNote(thys, lines, info, pos, last);
1115                 break;
1116 
1117             default:
1118                 ajFatal("Unknown descriptor type found in "
1119                         "showFillLines: %d",type);
1120 	}
1121     }
1122 
1123     ajListIterDel(&diter);
1124 
1125     return;
1126 }
1127 
1128 
1129 
1130 
1131 /* @funcstatic showMargin *****************************************************
1132 **
1133 ** Add a blank margin to the lines list
1134 **
1135 ** @param [r] thys [const EmbPShow] Show sequence object
1136 ** @param [u] lines [AjPList] list of lines to add to
1137 ** @return [void]
1138 **
1139 ** @release 1.0.0
1140 ** @@
1141 ******************************************************************************/
1142 
showMargin(const EmbPShow thys,AjPList lines)1143 static void showMargin(const EmbPShow thys, AjPList lines)
1144 {
1145     AjPStr marginfmt;
1146 
1147     marginfmt = ajStrNewRes(10);
1148 
1149     /* variable width margin */
1150     if(thys->margin)
1151     {
1152 	ajFmtPrintS(&marginfmt, "%%-%ds ", thys->margin-1);
1153 	ajListstrPushAppend(lines, ajFmtStr(ajStrGetPtr(marginfmt), ""));
1154     }
1155 
1156     ajStrDel(&marginfmt);
1157 
1158     return;
1159 }
1160 
1161 
1162 
1163 
1164 /* @funcstatic showMarginNumber ***********************************************
1165 ** Add a margin containing a number to the lines list
1166 **
1167 ** @param [r] thys [const EmbPShow] Show sequence object
1168 ** @param [u] lines [AjPList] list of lines to add to
1169 ** @param [r] number [ajint] number to display
1170 ** @return [void]
1171 **
1172 ** @release 1.0.0
1173 ** @@
1174 ******************************************************************************/
1175 
showMarginNumber(const EmbPShow thys,AjPList lines,ajint number)1176 static void showMarginNumber(const EmbPShow thys, AjPList lines, ajint number)
1177 {
1178     AjPStr marginfmt;
1179 
1180     marginfmt = ajStrNewRes(10);
1181 
1182     /* variable width margin containing a number */
1183     if(thys->margin)
1184     {
1185 	ajFmtPrintS(&marginfmt, "%%%dd ", thys->margin-1);
1186 	ajListstrPushAppend(lines, ajFmtStr(ajStrGetPtr(marginfmt), number));
1187     }
1188 
1189     ajStrDel(&marginfmt);
1190 
1191     return;
1192 }
1193 
1194 
1195 
1196 
1197 /* @funcstatic showPad ********************************************************
1198 **
1199 ** Add a set of space characters to the lines list to pad out an output line
1200 **
1201 ** @param [u] lines [AjPList] list of lines to add to
1202 ** @param [r] number [ajint] number of space characters to output
1203 ** @return [void]
1204 **
1205 ** @release 1.0.0
1206 ** @@
1207 ******************************************************************************/
1208 
showPad(AjPList lines,ajint number)1209 static void showPad(AjPList lines, ajint number)
1210 {
1211     AjPStr marginfmt;
1212 
1213     marginfmt=ajStrNewRes(10);
1214 
1215     /* variable width pad of spaces */
1216     if(number>0)
1217     {
1218 	ajFmtPrintS(&marginfmt, "%%-%ds", number);
1219 	ajListstrPushAppend(lines, ajFmtStr(ajStrGetPtr(marginfmt), ""));
1220     }
1221 
1222     ajStrDel(&marginfmt);
1223 
1224     return;
1225 }
1226 
1227 
1228 
1229 
1230 /* @func embShowUpperRange ****************************************************
1231 **
1232 ** Uppercase a string from a sequence with a range
1233 ** I.e ranges of a sequence are to be uppercased.
1234 ** We have a small region of the original sequence in a string.
1235 ** We want to uppercase any bits of the string that are in the ranges.
1236 **
1237 ** @param [u] line [AjPStr *] line to uppercase if it is in the ranges
1238 ** @param [r] upperrange [const AjPRange] range of original sequence
1239 **                                        to uppercase
1240 ** @param [r] pos [ajuint] position in sequence that line starts at
1241 ** @return [void]
1242 **
1243 ** @release 1.13.0
1244 ** @@
1245 ******************************************************************************/
1246 
embShowUpperRange(AjPStr * line,const AjPRange upperrange,ajuint pos)1247 void embShowUpperRange(AjPStr * line, const AjPRange upperrange, ajuint pos)
1248 {
1249     ajint nr;
1250     ajint i;
1251     ajuint j;
1252     ajuint start;			/* start of next range */
1253     ajuint end;				/* end of next range */
1254     ajint value;     /* code for type of overlap of range with line */
1255     char *p;	      /* ptr to start of range in line to uppercase */
1256 
1257     nr = ajRangeGetSize(upperrange);
1258 
1259     for(i=0; i<nr; i++)
1260     {
1261 	/* for each range in AjPRange upperrange */
1262 	ajRangeElementGetValues(upperrange, i, &start, &end);
1263 
1264 	/* get type of overlap */
1265 	value = ajRangeElementTypeOverlap(upperrange, i,
1266                                           pos, ajStrGetLen(*line));
1267 
1268 
1269 	ajDebug("embShowUpperRange %d %u..%u pos:%u len:%u value:%d\n",
1270 		i, start, end, pos, ajStrGetLen(*line), value);
1271 
1272 	/* complete overlap */
1273 	if(value == 2)
1274 	{
1275 	    ajStrFmtUpper(line);
1276 
1277 	    return;
1278 	}
1279 	else if(value)
1280 	{
1281 	    /* partial overlap */
1282 	    start--;       /* change start,end from human-readable position*/
1283 	    end--;
1284 
1285 	    if(start < pos)
1286 		start = pos;
1287 
1288 	    ajDebug("make uppercase start:%u end:%u pos:%u '%S'\n",
1289 		    start, end, pos, *line);
1290 	    p = ajStrGetuniquePtr(line)+start-pos;
1291 
1292 	    for(j=start; *p && j<=end; j++, p++)
1293 	    {
1294 		ajDebug("uppercase test pos:%u j:%u pos-j:%u\n",
1295 			pos, j, pos-j);
1296 
1297 		if(j-pos < ajStrGetLen(*line))
1298 		{
1299 		    ajDebug("uppercase char %u '%c'\n", pos-j, *p);
1300 		    *p = toupper((ajint) *p);
1301 		}
1302 	    }
1303 
1304 	    ajDebug("made uppercase start:%u pos:%u end:%u '%S'\n",
1305 		    start, end, pos, *line);
1306 	}
1307     }
1308 
1309     return;
1310 }
1311 
1312 
1313 
1314 
1315 /* @func embShowColourRange ***************************************************
1316 **
1317 ** colour a string from a sequence with a range
1318 ** I.e ranges of a sequence are to be coloured in HTML.
1319 ** We have a small region of the original sequence in a string.
1320 ** We want to colour any bits of the string that are in the ranges.
1321 **
1322 ** @param [u] line [AjPStr *] line to colour if it is in the ranges
1323 ** @param [r] colour [const AjPRange] range of original sequence to colour
1324 ** @param [r] pos [ajuint] position in sequence that line starts at
1325 ** @return [void]
1326 **
1327 ** @release 1.13.0
1328 ** @@
1329 ******************************************************************************/
1330 
embShowColourRange(AjPStr * line,const AjPRange colour,ajuint pos)1331 void embShowColourRange(AjPStr * line, const AjPRange colour, ajuint pos)
1332 {
1333     ajint nr;
1334     ajint i;
1335     ajuint start;			/* start of next range */
1336     ajuint end;				/* end of next range */
1337     ajint istart;
1338     ajint iend;
1339     ajint value;                        /* code for type of overlap of
1340 					   range with line */
1341     AjPStr html = NULL;
1342     AjPStr col = NULL;
1343 
1344     nr = ajRangeGetSize(colour);
1345 
1346     for(i=0; i<nr; i++)
1347     {
1348 	/* for each range in AjPRange colour */
1349 	ajRangeElementGetValues(colour, i, &start, &end);
1350 
1351 	/* get type of overlap */
1352 	value = ajRangeElementTypeOverlap(colour, i, pos, ajStrGetLen(*line));
1353 
1354 	/* partial or complete overlap */
1355 	if(value)
1356 	{
1357 	    istart = start - pos - 1;
1358 	    iend = end - pos - 1;
1359 
1360 	    if(istart < 0)
1361 		istart = 0;
1362 
1363 	    if(iend > (ajint)ajStrGetLen(*line)-1)
1364 		iend = ajStrGetLen(*line)-1;
1365 
1366 	    /* start */
1367 	    ajStrAssignC(&html, "<font color=");
1368 	    ajRangeElementGetText(colour, i, &col);
1369 
1370 	    if(ajStrGetLen(col))
1371 		ajStrAppendS(&html, col);
1372 	    else
1373 	    {
1374 		/* no colour, use 'red' as default */
1375 		ajStrAppendC(&html, "red");
1376 	    }
1377 
1378 	    ajStrAppendC(&html, ">");
1379 	    showInsertHTML(line, istart, html);
1380 
1381 	    /* end */
1382 	    ajStrAssignC(&html, "</font>");
1383 
1384 	    /* end+1 because want the tag after this position */
1385 	    showInsertHTML(line, iend+1, html);
1386 	}
1387     }
1388 
1389     ajStrDel(&col);
1390     ajStrDel(&html);
1391 
1392     return;
1393 }
1394 
1395 
1396 
1397 
1398 /* @funcstatic showInsertHTML *************************************************
1399 **
1400 ** Insert a string at a position in another string
1401 ** The position ignores any inserted HTML tags (anything between '<>')
1402 ** For example, insert "*" at position 3 of "<html tag>0123"
1403 ** gives "<html tag>012*3"
1404 **
1405 ** If the insert position is past the end of the string, it inserts at the end.
1406 **
1407 ** @param [u] target [AjPStr *] HTMLised string to insert into
1408 ** @param [r] pos [ajuint] position (ignoring HTML tags) to insert at
1409 ** @param [r] insert [const AjPStr] string to insert
1410 ** @return [void]
1411 **
1412 ** @release 1.0.0
1413 ** @@
1414 ******************************************************************************/
1415 
showInsertHTML(AjPStr * target,ajuint pos,const AjPStr insert)1416 static void showInsertHTML(AjPStr *target, ajuint pos, const AjPStr insert)
1417 {
1418     ajuint i;
1419     ajuint j;
1420     AjBool tag = ajFalse;
1421 
1422     /* find the required position, not including tags */
1423     for(i=0, j=0; j<pos && i<ajStrGetLen(*target); i++)
1424 	if(tag == ajFalse)
1425 	{
1426 	    if(ajStrGetPtr(*target)[i] == '<')
1427 		tag = ajTrue;
1428 	    else
1429 		j++;		    /* count the non-tag characters */
1430 	}
1431 	else
1432 	{
1433 	    if(ajStrGetPtr(*target)[i] == '>')
1434 		tag = ajFalse;
1435 	}
1436 
1437     /* we may have some tags at this position which still need to be skippped */
1438     while (ajStrGetPtr(*target)[i] == '<')
1439     {
1440     	while (ajStrGetPtr(*target)[i] != '>')
1441     	    i++;
1442         i++;
1443     }
1444 
1445 
1446     ajStrInsertS(target, i, insert);
1447 
1448     return;
1449 }
1450 
1451 
1452 
1453 
1454 /* @funcstatic showFillSeq ****************************************************
1455 **
1456 ** Add this line's worth of sequence to the lines list
1457 **
1458 ** @param [r] thys [const EmbPShow] Show sequence object
1459 ** @param [u] lines [AjPList] list of lines to add to
1460 ** @param [r] info [const EmbPShowSeq] data on how to display the sequence data
1461 ** @param [r] pos [ajuint] current printing position in the sequence
1462 ** @param [r] last [ajuint] last printing position in the sequence
1463 ** @return [void]
1464 **
1465 ** @release 1.0.0
1466 ** @@
1467 ******************************************************************************/
1468 
showFillSeq(const EmbPShow thys,AjPList lines,const EmbPShowSeq info,ajuint pos,ajuint last)1469 static void showFillSeq(const EmbPShow thys,
1470 			AjPList lines, const EmbPShowSeq info,
1471 			ajuint pos, ajuint last)
1472 {
1473     AjPStr line;
1474 
1475     AjPStr line1;	     /* used to make the three-letter codes */
1476     AjPStr line2;
1477     AjPStr line3;
1478     const char *p;
1479     const char *p3;
1480     ajuint count;
1481     ajuint width;
1482 
1483     ajDebug("showFillSeq\n");
1484 
1485     line = ajStrNewRes(81);
1486     width = last - pos + 1;
1487 
1488     /* variable width margin at left with optional number in it */
1489     if(info->number)
1490 	showMarginNumber(thys, lines, pos+thys->offset);
1491     else
1492 	showMargin(thys, lines);
1493 
1494     /* get the bit of the sequence to display */
1495     ajStrAppendSubS(&line, ajSeqGetSeqS(thys->seq), pos, last);
1496 
1497     /* change to three-letter code */
1498     if(!thys->nucleic && info->threeletter)
1499     {
1500 
1501 	line1=ajStrNewRes(81);
1502 	line2=ajStrNewRes(81);
1503 	line3=ajStrNewRes(81);
1504 
1505 	for(count=0, p=ajStrGetPtr(line);
1506 	    count < ajStrGetLen(line);
1507 	    count++, p++)
1508 	    if(*p == '*')
1509 	    {
1510 		ajStrAppendC(&line1, "*");
1511 		ajStrAppendC(&line2, "*");
1512 		ajStrAppendC(&line3, "*");
1513 	    }
1514 	    else if(!isalpha((ajint)*p))
1515 	    {
1516 		ajStrAppendC(&line1, "?");
1517 		ajStrAppendC(&line2, "?");
1518 		ajStrAppendC(&line3, "?");
1519 	    }
1520 	    else
1521 	    {
1522 		p3 = embPropCharToThree(*p);
1523 		ajStrAppendK(&line1, *p3);
1524 		ajStrAppendK(&line2, *(p3+1));
1525 		ajStrAppendK(&line3, *(p3+2));
1526 	    }
1527 
1528 	ajListstrPushAppend(lines, line1);
1529         line1 = NULL;
1530 	ajStrDel(&line);
1531 
1532     }
1533     else
1534     {
1535 	/*
1536 	** nucleic or single-letter code
1537 	** do uppercase ranges
1538 	*/
1539 	if(ajRangeCountOverlaps(info->upperrange, pos, width))
1540 	    embShowUpperRange(&line, info->upperrange, pos);
1541 
1542 	/* do colour ranges if we are displaying HTML*/
1543 	if(thys->html && ajRangeCountOverlaps(info->highlight, pos, width))
1544 	    embShowColourRange(&line, info->highlight, pos);
1545 
1546 	ajListstrPushAppend(lines, line);
1547         line = NULL;
1548     }
1549 
1550     /* optional number at right */
1551     if(info->number)
1552     {
1553 	/*
1554 	** if the sequence has ended we might have to fill out the end
1555 	** with blanks
1556 	*/
1557 	if(last >= ajSeqGetLen(thys->seq))
1558 	{
1559 	    showPad(lines, thys->width - ajSeqGetLen(thys->seq) + pos);
1560 	    ajListstrPushAppend(lines,
1561 			     ajFmtStr(" %d",
1562 				      ajSeqGetLen(thys->seq)+thys->offset-1));
1563 	}
1564 	else
1565 	    ajListstrPushAppend(lines,
1566 			     ajFmtStr(" %d",
1567 				      pos+width+thys->offset-1));
1568     }
1569 
1570     /* end the output line */
1571     ajListstrPushAppend(lines, ajFmtStr("\n"));
1572 
1573 
1574     /* if three-letter code, add the other 3-letter output lines */
1575     if(!thys->nucleic && info->threeletter)
1576     {
1577 	showMargin(thys, lines);
1578 	ajListstrPushAppend(lines, line2);
1579         line2 = NULL;
1580 	ajListstrPushAppend(lines, ajFmtStr("\n"));
1581 	showMargin(thys, lines);
1582 	ajListstrPushAppend(lines, line3);
1583         line3 = NULL;
1584 	ajListstrPushAppend(lines, ajFmtStr("\n"));
1585     }
1586 
1587     return;
1588 }
1589 
1590 
1591 
1592 
1593 /* @funcstatic showFillBlank **************************************************
1594 **
1595 ** Add a blank line to the lines list
1596 **
1597 ** @param [r] thys [const EmbPShow] Show sequence object
1598 ** @param [u] lines [AjPList] list of lines to add to
1599 ** @param [r] info [const EmbPShowBlank] data on how to display the
1600 **                                       sequence data
1601 ** @param [r] pos [ajuint] current printing position in the sequence
1602 ** @param [r] last [ajuint] last printing position in the sequence
1603 ** @return [void]
1604 **
1605 ** @release 1.0.0
1606 ** @@
1607 ******************************************************************************/
1608 
showFillBlank(const EmbPShow thys,AjPList lines,const EmbPShowBlank info,ajuint pos,ajuint last)1609 static void showFillBlank(const EmbPShow thys,
1610 			  AjPList lines, const EmbPShowBlank info,
1611 			  ajuint pos,ajuint last)
1612 {
1613     AjPStr line;
1614 
1615     ajDebug("showFillBlank\n");
1616 
1617     (void) thys;			/* make it used */
1618     (void) info;			/* make it used */
1619     (void) pos;				/* make it used */
1620     (void) last;			/* make it used */
1621 
1622     line = ajStrNewRes(2);
1623 
1624     ajStrAssignC(&line, "\n");
1625     ajListstrPushAppend(lines, line);
1626     line = NULL;
1627     return;
1628 }
1629 
1630 
1631 
1632 
1633 /* @funcstatic showFillTicks **************************************************
1634 **
1635 ** Add a tick line to the lines list
1636 **
1637 ** @param [r] thys [const EmbPShow] Show sequence object
1638 ** @param [u] lines [AjPList] list of lines to add to
1639 ** @param [r] info [const EmbPShowTicks] data on how to display the
1640 **                                      sequence data
1641 ** @param [r] pos [ajuint] current printing position in the sequence
1642 ** @param [r] last [ajuint] last printing position in the sequence
1643 ** @return [void]
1644 **
1645 ** @release 1.0.0
1646 ** @@
1647 ******************************************************************************/
1648 
showFillTicks(const EmbPShow thys,AjPList lines,const EmbPShowTicks info,ajuint pos,ajuint last)1649 static void showFillTicks(const EmbPShow thys,
1650 			  AjPList lines, const EmbPShowTicks info,
1651 			  ajuint pos,ajuint last)
1652 {
1653     AjPStr line;
1654     ajuint i;
1655     ajuint offset;
1656     ajuint width;
1657 
1658     ajDebug("showFillTicks\n");
1659 
1660     (void) info;			/* make it used */
1661 
1662     line   = ajStrNewRes(81);
1663     offset = thys->offset;
1664     width  = last - pos + 1;
1665 
1666 
1667     /* make the ticks line */
1668     for(i=pos+offset; i<pos+offset+width; i++)
1669 	if(!(i % 10))
1670 	    ajStrAppendC(&line, "|");
1671 	else if(!(i % 5))
1672 	    ajStrAppendC(&line, ":");
1673 	else
1674 	    ajStrAppendC(&line, "-");
1675 
1676     showMargin(thys, lines);
1677     ajListstrPushAppend(lines, line);
1678     line = NULL;
1679     /* end the output ticks line */
1680     ajListstrPushAppend(lines, ajFmtStr("\n"));
1681 
1682     return;
1683 }
1684 
1685 
1686 
1687 
1688 /* @funcstatic showFillTicknum ************************************************
1689 **
1690 ** Add a tick line numbers to the lines list
1691 **
1692 ** @param [r] thys [const EmbPShow] Show sequence object
1693 ** @param [u] lines [AjPList] list of lines to add to
1694 ** @param [r] info [const EmbPShowTicknum] data on how to display
1695 **                 the sequence data
1696 ** @param [r] pos [ajuint] current printing position in the sequence
1697 ** @param [r] last [ajuint] last printing position in the sequence
1698 ** @return [void]
1699 **
1700 ** @release 1.0.0
1701 ** @@
1702 ******************************************************************************/
1703 
showFillTicknum(const EmbPShow thys,AjPList lines,const EmbPShowTicknum info,ajuint pos,ajuint last)1704 static void showFillTicknum(const EmbPShow thys,
1705 			    AjPList lines, const EmbPShowTicknum info,
1706 			    ajuint pos, ajuint last)
1707 {
1708     AjPStr line;
1709     ajuint i;
1710     ajuint offset;
1711     ajuint width;
1712     ajuint pad;
1713 
1714     ajDebug("showFillTicknum\n");
1715 
1716     (void) info;			/* make it used */
1717 
1718     line   = ajStrNewRes(81);
1719     offset = thys->offset;
1720     width  = last - pos + 1;
1721 
1722     showMargin(thys, lines);
1723     pad = 9 - ((pos+offset-1) % 10);
1724 
1725     if(pad)
1726 	showPad(lines, pad);
1727 
1728     for(i=pos + offset + pad; i < pos+offset+width; i+=10)
1729 	ajFmtPrintAppS(&line, "%-10d", i);
1730 
1731     ajListstrPushAppend(lines, line);
1732     line = NULL;
1733     /* end the output line */
1734     ajListstrPushAppend(lines, ajFmtStr("\n"));
1735 
1736     return;
1737 }
1738 
1739 
1740 
1741 
1742 /* @funcstatic showFillComp ***************************************************
1743 **
1744 ** Add thys line's worth of sequence complement to the lines list
1745 **
1746 ** @param [r] thys [const EmbPShow] Show sequence object
1747 ** @param [u] lines [AjPList] list of lines to add to
1748 ** @param [r] info [const EmbPShowComp] data on how to display the
1749 **                                     sequence data
1750 ** @param [r] pos [ajuint] current printing position in the sequence
1751 ** @param [r] last [ajuint] last printing position in the sequence
1752 ** @return [void]
1753 **
1754 ** @release 1.0.0
1755 ** @@
1756 ******************************************************************************/
1757 
showFillComp(const EmbPShow thys,AjPList lines,const EmbPShowComp info,ajuint pos,ajuint last)1758 static void showFillComp(const EmbPShow thys,
1759 			 AjPList lines, const EmbPShowComp info,
1760 			 ajuint pos, ajuint last)
1761 {
1762     AjPStr line;
1763     ajuint width;
1764 
1765     ajDebug("showFillComp\n");
1766 
1767     line = ajStrNewRes(81);
1768     width = last - pos + 1;
1769 
1770     /*
1771     ** do a quick check that we have a nucleic sequence
1772     ** - else just ignore this
1773     */
1774     if(!thys->nucleic)
1775 	return;
1776 
1777     /* variable width margin at left with optional number in it */
1778     if(info->number)
1779 	showMarginNumber(thys, lines, pos+thys->offset);
1780     else
1781 	showMargin(thys, lines);
1782 
1783 
1784     /* get the sequence at this position */
1785     ajStrAppendSubS(&line, ajSeqGetSeqS(thys->seq), pos, pos+width-1);
1786 
1787     /* get the complement */
1788     ajSeqstrComplement(&line);
1789     ajListstrPushAppend(lines, line);
1790     line = NULL;
1791 
1792     /* optional number at right */
1793     if(info->number)
1794     {
1795 	/*
1796 	** if the sequence has ended we might have to fill
1797 	** out the end with blanks
1798 	*/
1799 	if(last >= ajSeqGetLen(thys->seq))
1800 	{
1801 	    showPad(lines, thys->width - ajSeqGetLen(thys->seq) + pos);
1802 	    ajListstrPushAppend(lines,
1803 			     ajFmtStr(" %d",
1804 				      ajSeqGetLen(thys->seq)+thys->offset-1));
1805 	}
1806 	else
1807 	    ajListstrPushAppend(lines, ajFmtStr(" %d",
1808 					     pos+width+thys->offset-1));
1809     }
1810 
1811     /* end the output line */
1812     ajListstrPushAppend(lines, ajFmtStr("\n"));
1813 
1814     return;
1815 }
1816 
1817 
1818 
1819 
1820 /* @funcstatic showFillTran ***************************************************
1821 **
1822 ** Add this line's worth of sequence translation to the lines list
1823 **
1824 ** @param [r] thys [const EmbPShow] Show sequence object
1825 ** @param [u] lines [AjPList] list of lines to add to
1826 ** @param [u] info [EmbPShowTran] data on how to display the
1827 **                          sequence data
1828 ** @param [r] pos [ajuint] current printing position in the sequence
1829 ** @param [r] last [ajuint] last printing position in the sequence
1830 ** @return [void]
1831 **
1832 ** @release 1.0.0
1833 ** @@
1834 ******************************************************************************/
1835 
showFillTran(const EmbPShow thys,AjPList lines,EmbPShowTran info,ajuint pos,ajuint last)1836 static void showFillTran(const EmbPShow thys,
1837 			 AjPList lines, EmbPShowTran info,
1838 			 ajuint pos, ajuint last)
1839 {
1840 
1841     AjPStr line;
1842     AjPSeq tran   = NULL;
1843     AjPSeq seq    = NULL; /* local copy of sequence for translating ranges */
1844     AjPStr temp = NULL;
1845     AjPStr tmpaa =NULL;	  /* peptide expanded to 3-let code or by 2 spaces */
1846     AjPStr transeq =NULL; /* sequence copy for editing */
1847     ajint frame;
1848     ajuint framepad = 0; /* no. of spaces to pad to the correct frame pos */
1849     ajuint linepos;
1850     ajuint startpos;	  /* number at start of line */
1851     ajuint endpos;	  /* number at end of line */
1852     ajuint i;
1853     ajint j;
1854     ajint orflast;
1855 
1856     ajDebug("showFillTran pos:%u last:%u\n", pos, last);
1857 
1858     line = ajStrNewRes(81);
1859 
1860     /*
1861     **  do a quick check that we have a nucleic sequence - else just
1862     **  ignore this
1863     */
1864     if(!thys->nucleic)
1865 	return;
1866 
1867 
1868     /* if the translation has not yet been done, do it now - once only */
1869     if(!info->transeq)
1870     {
1871 	/* translate a set of ranges ... using frame number */
1872 	if(info->regions && ajRangeGetSize(info->regions))
1873 	{
1874 	    frame = info->frame;
1875 
1876             /* shift the translation to the correct frame */
1877             if(frame == 1 || frame == 5)
1878                 framepad = 0;
1879             else if(frame == 2 || frame == 6)
1880                 framepad = 1;
1881             else if(frame == 3 || frame == 4)
1882                 framepad = 2;
1883 
1884             framepad = 0;
1885 	    seq = ajSeqNewSeq(thys->seq);
1886 	    tran = ajRangeSeqExtractPep(info->regions, seq,
1887                                         info->trnTable, frame);
1888 
1889 	    /* expand to fill line or change to three-letter code */
1890 	    if(info->threeletter)
1891 	    {
1892 		tmpaa = embPropProt1to3(tran,framepad);
1893 		ajSeqAssignSeqS(tran, tmpaa);
1894 	    }
1895 	    else
1896 	    {
1897 		/* pad with 2 spaces after every residue */
1898 		tmpaa = embPropProtGaps(tran,framepad);
1899 		ajSeqAssignSeqS(tran,tmpaa);
1900 	    }
1901 	    ajStrDel(&tmpaa);
1902 
1903 	    /*
1904 	    **  now put in spaces to align the translation to the
1905 	    **  sequence ranges
1906 	    */
1907 	    ajRangeSeqStuffPep(info->regions, tran, frame);
1908 	    ajStrSetClear(&temp);
1909 	/* store the resulting translation in our descriptor structure */
1910             info->transeq = tran;
1911             ajSeqDel(&seq);
1912 	}
1913 	else
1914 	{
1915 	    /* ... or just translate in the required frame */
1916 
1917 	    /*
1918 	    **  change frames -1 to -3 to frames 4 to 6 for translation
1919 	    **  of complement (NB that really should say just 'complement', not
1920 	    **  'reverse-complement' as we will be putting the resulting
1921 	    **  reversed peptide under the forward nucleic sequence.)
1922 	    */
1923 	    frame = info->frame;
1924 
1925 	    if(frame < 0)
1926 		frame = 3-frame;
1927 
1928 	    /* do the translation */
1929 	    tran = ajTrnSeqOrig(info->trnTable, thys->seq, frame);
1930 
1931 	    /* shift the translation to the correct frame */
1932 	    if(frame == 1 || frame == 5)
1933 		framepad = 0;
1934 	    else if(frame == 2 || frame == 6)
1935 		framepad = 1;
1936 	    else if(frame == 3 || frame == 4)
1937 		framepad = 2;
1938 
1939 	    /* convert inter-ORF regions to '-'s or put it in lower case*/
1940 	    orflast = -1;
1941 
1942 	    /*
1943 	       for(i=0; i<ajSeqGetLen(tran); i++)
1944 	       if(ajStrGetPtr(ajSeqGetSeqS(tran))[i] == '*')
1945 	       {
1946 		   if(i-orflast < info->orfminsize+1)
1947 		   {
1948 		       if(info->lcinterorf)
1949 			   for(j=orflast+1; j<i; j++)
1950 			       ajStrGetPtr(ajSeqGetSeqS(tran))[j] =
1951 			       tolower((ajint) ajStrGetPtr(ajSeqGetSeqS(tran))
1952                                [j]);
1953 		       else
1954 			   for(j=orflast+1; j<i; j++)
1955 			       ajStrGetPtr(ajSeqGetSeqS(tran))[j] = '-';
1956 		   }
1957 		   orflast = i;
1958 	       }
1959 	     */
1960 
1961 	    /* Thomas version */
1962 	    if(frame < 4)
1963 	    {
1964 		transeq = ajSeqGetSeqCopyS(tran);
1965 
1966 		for(i=0; i<ajStrGetLen(transeq); i++)
1967 		    if(ajStrGetCharPos(transeq,i) == '*')
1968 		    {
1969 			if(i-orflast < info->orfminsize+1)
1970 			{
1971 			    if(!(info->firstorf && orflast == -1))
1972 			    {
1973 				j = orflast+1;
1974 
1975 				if(info->lcinterorf)
1976 				    ajStrFmtLowerSub(&transeq,j,i-1);
1977 				else
1978 				    ajStrPasteCountK(&transeq,j,'-',i-j);
1979 			    }
1980 			}
1981 
1982 			orflast = i;
1983 		    }
1984 
1985 		/* put the last ORF in lower case or convert it to -'s */
1986 		if(i == ajStrGetLen(transeq) && !(info->lastorf)
1987 		   && i-orflast < info->orfminsize+1)
1988 		{
1989 		    j = orflast+1;
1990 		    if(info->lcinterorf)
1991 			ajStrFmtLowerSub(&transeq,j,i-1);
1992 		    else
1993 			ajStrPasteCountK(&transeq,j,'-',i-j);
1994 		}
1995 
1996 		ajSeqAssignSeqS(tran, transeq);
1997 		ajStrDel(&transeq);
1998 	    }
1999 	    else /* frame 4,5,6 */
2000 	    {
2001 		transeq = ajSeqGetSeqCopyS(tran);
2002 
2003 		for(i=0; i<ajStrGetLen(transeq); i++)
2004 		    if(ajStrGetCharPos(transeq,i) == '*')
2005 		    {
2006 			if(i-orflast < info->orfminsize+1)
2007 			    if(!(info->lastorf && orflast == -1))
2008 			    {
2009 				j = orflast+1;
2010 				if(info->lcinterorf)
2011 				    ajStrFmtLowerSub(&transeq,j,i-1);
2012 				else
2013 				    ajStrPasteCountK(&transeq,j,'-',i-j);
2014 			    }
2015 
2016 			orflast = i;
2017 		    }
2018 
2019 		/* put the first ORF in lower case or convert it to -'s */
2020 		if(i == ajSeqGetLen(tran) && !(info->firstorf)
2021 		   && i-orflast < info->orfminsize+1)
2022 		{
2023 		    j = orflast+1;
2024 		    if(info->lcinterorf)
2025 			ajStrFmtLowerSub(&transeq,j,i-1);
2026 		    else
2027 			ajStrPasteCountK(&transeq,j,'-',i-j);
2028 		}
2029 
2030 		ajSeqAssignSeqS(tran, transeq);
2031 		ajStrDel(&transeq);
2032 	    }
2033 
2034 	    /* expand to fill line or change to three-letter code */
2035 	    if(info->threeletter)
2036 	    {
2037 		if(info->frame > 0)
2038                     tmpaa = embPropProt1to3(tran,framepad);
2039                 else
2040                     tmpaa = embPropProt1to3Rev(tran,framepad);
2041 
2042 		ajSeqAssignSeqS(tran,tmpaa);
2043 	    }
2044 	    else
2045 	    {
2046 		tmpaa = embPropProtGaps(tran,framepad);
2047 
2048 		/* pad with 2 spaces after every residue */
2049 		ajSeqAssignSeqS(tran,tmpaa);
2050 	    }
2051 
2052 	    ajStrDel(&tmpaa);
2053 	/* store the resulting translation in our descriptor structure */
2054             info->transeq = tran;
2055 	}
2056 
2057     }
2058 
2059     /* get the sequence at this position */
2060     if(pos < ajSeqGetLen(info->transeq))
2061         ajStrAppendSubS(&line, ajSeqGetSeqS(info->transeq),
2062                         pos, last);
2063 
2064     /* get the number of the starting and ending amino-acid on this line */
2065     startpos = info->tranpos;
2066     endpos = info->tranpos;
2067 
2068     for(linepos=0; linepos<ajStrGetLen(line); linepos++)
2069 	/*
2070 	**  only count the starting letter of 3-letter codes and don't
2071 	**  count *'s
2072 	*/
2073 	if(ajStrGetPtr(line)[linepos] >= 'A' &&
2074 	   ajStrGetPtr(line)[linepos] <= 'Z')
2075 	    info->tranpos++;
2076 
2077     /* less than width in the line? Add blanks to pad it out */
2078     for(;linepos < thys->width; linepos++)
2079 	ajStrAppendC(&line, " ");
2080 
2081     /* if at least one residue, count it at start */
2082     if(info->tranpos != endpos)
2083 	startpos++;
2084 
2085 
2086     /* variable width margin at left with optional number in it */
2087     if(info->number)
2088 	showMarginNumber(thys, lines, startpos);
2089     else
2090 	showMargin(thys, lines);
2091 
2092 
2093     /* put the translation line on the output list */
2094     ajListstrPushAppend(lines, line);
2095     line = NULL;
2096 
2097     /* optional number at right */
2098     if(info->number)
2099 	ajListstrPushAppend(lines, ajFmtStr(" %d", info->tranpos));
2100 
2101     if(info->showframe)
2102     {
2103 	frame = info->frame;
2104 	if(frame < 0)
2105 	    frame = 3 - frame;
2106 	ajListstrPushAppend(lines, ajFmtStr("%4s%d", "F", frame));
2107     }
2108 
2109     /* end the output line */
2110     ajListstrPushAppend(lines, ajFmtStr("\n"));
2111 
2112     return;
2113 }
2114 
2115 
2116 
2117 
2118 /* @funcstatic showFillRE *****************************************************
2119 **
2120 ** Add this line's worth of Restriction Enzyme cut sites to the lines list
2121 **
2122 ** @param [r] thys [const EmbPShow] Show sequence object
2123 ** @param [u] lines [AjPList] list of lines to add to
2124 ** @param [u] info [EmbPShowRE] data on how to display the RE cut sites
2125 ** @param [r] pos [ajuint] current printing position in the sequence
2126 ** @param [r] last [ajuint] last printing position in the sequence
2127 ** @return [void]
2128 **
2129 ** @release 1.0.0
2130 ** @@
2131 ******************************************************************************/
2132 
showFillRE(const EmbPShow thys,AjPList lines,EmbPShowRE info,ajuint pos,ajuint last)2133 static void showFillRE(const EmbPShow thys,
2134 		       AjPList lines, EmbPShowRE info,
2135 		       ajuint pos, ajuint last)
2136 {
2137     ajDebug("showFillRE\n");
2138 
2139     /*
2140     **  do a quick check that we have a nucleic sequence - else just ignore
2141     **  this
2142     */
2143     if(!thys->nucleic)
2144 	return;
2145 
2146     if(info->flat)
2147 	showFillREflat(thys, lines, info, pos, last);
2148     else
2149 	showFillREupright(thys, lines, info, pos, last);
2150 
2151     return;
2152 }
2153 
2154 
2155 
2156 
2157 /* @funcstatic showFillREupright **********************************************
2158 **
2159 ** Add this line's worth of Restriction Enzyme cut sites to the lines list
2160 ** Display in upright sit-up-and-beg format
2161 **
2162 ** @param [r] thys [const EmbPShow] Show sequence object
2163 ** @param [u] lines [AjPList] list of lines to add to
2164 ** @param [u] info [EmbPShowRE] data on how to display the RE cut sites
2165 ** @param [r] pos [ajuint] current printing position in the sequence
2166 ** @param [r] last [ajuint] last printing position in the sequence
2167 ** @return [void]
2168 **
2169 ** @release 1.0.0
2170 ** @@
2171 ******************************************************************************/
2172 
showFillREupright(const EmbPShow thys,AjPList lines,EmbPShowRE info,ajuint pos,ajuint last)2173 static void showFillREupright(const EmbPShow thys,
2174 			      AjPList lines, EmbPShowRE info,
2175 			      ajuint pos, ajuint last)
2176 {
2177     AjPStr line    = NULL;
2178     AjPStr newline = NULL;
2179     AjPStr baseline;			/* line holding first set of ticks */
2180     AjPList linelist;			/* list of lines to fill */
2181     ajuint cut;				/* the sites to display */
2182     AjIList liter;			/* iterator for linelist */
2183     AjBool freespace;			/* flag: found free space to print */
2184     EmbPMatMatch m = NULL;		/* restriction enz match structure */
2185     AjIList miter;			/* iterator for matches list */
2186     EmbPShowREsite sitenode;		/* site node structure */
2187     AjIList siter;			/* iterator for sites list */
2188     EmbPShowREsite s = NULL;		/* site node structure */
2189     AjPStr tick = NULL;			/* tick "|" string */
2190     ajint ln;
2191     void* sajb = NULL;
2192 
2193     linelist = ajListstrNew();
2194     baseline = ajStrNew();
2195 
2196     /* if not yet produced a sorted list of cut sites, do it now */
2197     if(info->sitelist == NULL)
2198     {
2199 	info->sitelist = ajListNew();
2200 
2201 	miter = ajListIterNewread(info->matches);
2202 
2203 	while((m = ajListIterGet(miter)) != NULL)
2204 	{
2205 	    /* store the first cut site in this sense */
2206 	    if(info->sense == 1)	/* forward sense */
2207 		cut = m->cut1;
2208 	    else			/* reverse sense */
2209 		cut = m->cut2;
2210 
2211 	    cut--;
2212 
2213 	    AJNEW0(sitenode);
2214 	    sitenode->pos = cut;
2215 	    sitenode->name = m->cod;
2216 	    ajListPushAppend(info->sitelist, sitenode);
2217 
2218 	    /* now store the potential second cut site on this sense */
2219 	    if(info->sense == 1)	/* forward sense */
2220 		cut = m->cut3;
2221 	    else			/* reverse sense */
2222 		cut = m->cut4;
2223 
2224 	    if(cut)
2225 	    {
2226 		cut--;
2227 		AJNEW0(sitenode);
2228 		sitenode->pos  = cut;
2229 		sitenode->name = m->cod;
2230 		ajListPushAppend(info->sitelist, sitenode);
2231 	    }
2232 	}
2233 
2234 	ajListIterDel(&miter);
2235 	ajListSort(info->sitelist, &showFillREuprightSort);
2236     }
2237 
2238     ajStrAssignC(&tick, "|");		/* a useful string */
2239 
2240     /* iterate through the site list */
2241     siter = ajListIterNewread(info->sitelist);
2242 
2243     while((s = ajListIterGet(siter)) != NULL)
2244     {
2245 	cut = s->pos;
2246 
2247 	/* ignore this match if nothing is to be displayed on this line */
2248 	if(cut >= pos && cut <= last)
2249 	{
2250 
2251 	    /* convert to position in the line */
2252 	    cut = cut-pos;
2253 
2254 	    /* put tick in base line */
2255 	    showOverPrint(&baseline, cut, tick);
2256 
2257 	    /* work up list of lines */
2258 	    freespace = ajFalse;
2259 
2260 	    /*
2261 	    **  potentially updating the nodes of linelist, so
2262 	    **  don't just iterate, use ajListstrPop and ajListstrPushApp
2263 	    **  to pop off the bottom and then push the altered node back on
2264 	    **  the top of the list
2265 	    */
2266 	    for(ln = (ajuint) ajListstrGetLength(linelist); ln>0; ln--)
2267 	    {
2268 		ajListstrPop(linelist, &line);
2269 		/*
2270 		**  if not yet written the name in this set of
2271 		**  iterations, see if if it can be done so now
2272 		*/
2273 		if(!freespace)
2274 		{
2275 		    /* if name space is clear, write name and break */
2276 		    if(showLineIsClear(&line, cut, cut+ajStrGetLen(s->name)))
2277 		    {
2278 			showOverPrint(&line, cut, s->name);
2279 
2280 			/* flag to show we have written name */
2281 			freespace = ajTrue;
2282 		    }
2283 		    else
2284 			/*
2285 			**  if cut site position character is space, change
2286 			**  it to a tick
2287 			*/
2288 			if(*(ajStrGetPtr(line)+cut) == ' ')
2289 			    showOverPrint(&line, cut, tick);
2290 		}
2291 
2292 		ajListstrPushAppend(linelist, line);
2293                 line = NULL;
2294 
2295 		/* end 'iteration' through lines */
2296 	    }
2297 
2298 
2299 	    /* if name was not written, append a new line and write name */
2300 	    if(!freespace)
2301 	    {
2302 		newline=ajStrNew();
2303 		showOverPrint(&newline, cut, s->name);
2304 		ajListstrPushAppend(linelist, newline);
2305                 newline = NULL;
2306 	    }
2307 	}
2308     }
2309 
2310     ajListIterDel(&siter);
2311 
2312 
2313     /* convert base line ticks to forward or reverse slashes */
2314     if(info->sense == 1)		/* forward sense */
2315 	ajStrExchangeSetCC(&baseline, "|", "\\");
2316     else				/* reverse sense */
2317 	ajStrExchangeSetCC(&baseline, "|", "/");
2318 
2319 
2320     /* put base line at start of lines list */
2321     ajListstrPush(linelist, baseline);
2322     baseline = NULL;
2323 
2324     /*
2325     **  reverse the order of the lines if we are in the forward sense as
2326     **  then we get the ticks pointing downwards :-)
2327     */
2328     if(info->sense == 1) ajListstrReverse(linelist);
2329 
2330     /* iterate through the lines and print them */
2331     liter = ajListIterNewread(linelist);
2332 
2333     while((line = ajListIterGet(liter)) != NULL)
2334     {
2335 	/* output to the lines list */
2336 	/* variable width margin at left */
2337 	/* with optional number in it */
2338 	showMargin(thys, lines);
2339 	/* put the translation line */
2340 	/* on the output list */
2341 	ajListstrPushAppend(lines, line);
2342         line = NULL;
2343 	/* end the output line */
2344 	ajListstrPushAppend(lines, ajFmtStr("\n"));
2345     }
2346 
2347     ajListIterDel(&liter);
2348 
2349     while(ajListPop(linelist,&sajb));
2350 
2351     ajListstrFree(&linelist);
2352     ajStrDel(&tick);
2353 
2354     return;
2355 }
2356 
2357 
2358 
2359 
2360 /* @funcstatic showFillREuprightSort ******************************************
2361 **
2362 ** Sort routine for showFillREupright - produces reverse cut site order
2363 **
2364 ** @param [r] a [const void*] First pos
2365 ** @param [r] b [const void*] Second pos
2366 ** @return [ajint] Comparison value. 0 if equal, -1 if first is lower,
2367 **               +1 if first is higher.
2368 **
2369 ** @release 1.0.0
2370 ** @@
2371 ******************************************************************************/
2372 
showFillREuprightSort(const void * a,const void * b)2373 static ajint showFillREuprightSort(const void* a, const void* b)
2374 {
2375     ajint res;
2376 
2377     res = (*(EmbPShowREsite const *)b)->pos -
2378 	(*(EmbPShowREsite const *)a)->pos;
2379 
2380     /* if the cut sites are equal, reverse sort by the length of the name */
2381     if(!res)
2382 	res = ajStrGetLen((*(EmbPShowREsite const *)b)->name) -
2383 	    ajStrGetLen((*(EmbPShowREsite const *)a)->name);
2384 
2385     return res;
2386 }
2387 
2388 
2389 
2390 
2391 /* @funcstatic showFillREflat *************************************************
2392 **
2393 ** Add this line's worth of Restriction Enzyme cut sites to the lines list
2394 ** Display in flat format with recognition sites
2395 **
2396 ** @param [r] thys [const EmbPShow] Show sequence object
2397 ** @param [u] lines [AjPList] list of lines to add to
2398 ** @param [r] info [const EmbPShowRE] data on how to display the RE cut sites
2399 ** @param [r] pos [ajuint] current printing position in the sequence
2400 ** @param [r] last [ajuint] last printing position in the sequence
2401 ** @return [void]
2402 **
2403 ** @release 1.0.0
2404 ** @@
2405 ******************************************************************************/
2406 
showFillREflat(const EmbPShow thys,AjPList lines,const EmbPShowRE info,ajuint pos,ajuint last)2407 static void showFillREflat(const EmbPShow thys,
2408 			   AjPList lines, const EmbPShowRE info,
2409 			   ajuint pos, ajuint last)
2410 {
2411     AjPStr line  = NULL;
2412     AjPStr line2 = NULL;
2413     AjPList linelist = NULL;		/* list of lines to fill */
2414     ajuint start;
2415     ajuint end;  			/* start and end position of site */
2416     ajuint nameend;			/* end position of name */
2417     ajuint base;		   /* base position of binding site */
2418     ajint cut1;
2419     ajint cut2;
2420     ajint cut3;
2421     ajint cut4;
2422     AjIList liter;			/* iterator for linelist */
2423     AjPStr namestr = NULL;		/* name of RE to insert into line */
2424     AjPStr sitestr = NULL;		/* binding and cut site to insert */
2425     ajuint i;
2426     const char *claimchar = "*";        /* char used to stake a claim to */
2427 					/* that position in the string */
2428     AjBool freespace;			/* flag for found a free space to
2429 					   print in */
2430     EmbPMatMatch m = NULL;		/* restriction enzyme match struct */
2431     AjIList miter;			/* iterator for matches list */
2432     ajuint ln;
2433     void* sajb = NULL;
2434     ajuint width;
2435 
2436     width = last - pos + 1;
2437 
2438     linelist = ajListstrNew();
2439 
2440     /* iterate through the list */
2441     miter = ajListIterNewread(info->matches);
2442 
2443     while((m = ajListIterGet(miter)) != NULL)
2444     {
2445 	/* get the start and end positions */
2446 	cut1 = m->cut1;
2447 	/* the display points back '<' at cut pos */
2448 	cut2 = m->cut2+1;
2449 	cut3 = m->cut3;
2450 	cut4 = m->cut4;
2451 
2452 	if(m->cut4)
2453 	    cut4++;		/* the display points back '<' at cut pos */
2454 
2455 	base = m->start;
2456 	start = base;
2457 
2458 	ajDebug("showFillRE start:%d sense:%b plasmid:%b circ12:%b 34:%b\n",
2459 		start, info->sense, info->plasmid, m->circ12, m->circ34);
2460 	ajDebug("           cut1:%d 2:%d 3:%d 4:%d\n",
2461 		cut1, cut2, cut3, cut4);
2462 
2463 	if(info->sense == 1)
2464 	{				/* forward sense */
2465 	    if(info->plasmid || !m->circ12)
2466 		if(cut1 < (ajint)start)
2467 		    start = cut1;
2468 
2469 	    if(info->plasmid || !m->circ34)
2470 		if(cut3 && cut3 < (ajint)start)
2471 		start = cut3;
2472 	}
2473 	else
2474 	{				/* reverse sense */
2475 	    if(info->plasmid || !m->circ12)
2476 		if(cut2 < (ajint)start)
2477 		    start = cut2;
2478 
2479 	    if(info->plasmid || !m->circ34)
2480 		if(cut4 && cut4 < (ajint)start)
2481 		    start = cut4;
2482 	}
2483 
2484 	end = base + ajStrGetLen(m->pat)-1;
2485 	ajDebug("showFillRE end: %d base: %d patlen: %d pat: '%S'\n",
2486 		end, base, ajStrGetLen(m->pat), m->pat);
2487 
2488 	nameend = base + ajStrGetLen(m->cod)-1;
2489 
2490 	if(info->sense == 1)
2491 	{				/* forward sense */
2492 	    ajDebug("showFillRE fwd end: %d cut1:%d cut3:%d\n",
2493 		    end, cut1, cut3);
2494 
2495 	    if(info->plasmid || !m->circ12)
2496 		if(cut1 > (ajint)end)
2497 		    end = cut1;
2498 
2499 	    if(info->plasmid || !m->circ34)
2500 		if(cut3 && cut3 > (ajint)end)
2501 		    end = cut3;
2502 
2503 	    ajDebug("showFillRE fwd set end: %d\n",
2504 		    end);
2505 	}
2506 	else
2507 	{				/* reverse sense */
2508 	    ajDebug("showFillRE rev end: %d cut2:%d cut4:%d\n",
2509 		    end, cut2, cut4);
2510 
2511 	    if(info->plasmid || !m->circ12)
2512 		if(cut2 > (ajint)end)
2513 		    end = cut2;
2514 
2515 	    if(info->plasmid || !m->circ34)
2516 		if(cut4 && cut4 > (ajint)end)
2517 		    end = cut4;
2518 
2519 	    ajDebug("showFillRE rev set end: %d\n",
2520 		    end);
2521 	}
2522 
2523 	/* convert human-readable sequence positions to string positions */
2524 	start--;
2525 	end--;
2526 	base--;
2527 	nameend--;
2528 
2529 	ajDebug("showFillREFlat start:%d end:%d pos:%d width:%d\n",
2530 		start, end, pos, width);
2531 
2532 	/* ignore this match if nothing is to be displayed on this line */
2533 	if(start <= last && end >= pos)
2534 	{
2535 	    ajDebug("showFillREFlat site within range\n");
2536 
2537 	    /* make a standard name and site string to be chopped up later */
2538 
2539 	    /* site string stuff */
2540 	    /* initial string of '.'s */
2541 	    sitestr = ajStrNew();
2542 	    ajStrAppendCountK(&sitestr, '.', end-start+1 );
2543 	    ajDebug("showFillREFlat ajStrAppKI '.' %d\n", end-start+1);
2544 
2545 	    /*
2546 	    **  add on any claim characters required to stake a claim to
2547 	    **  positions used by the name
2548 	    */
2549 	    if(nameend > end)
2550 	    {
2551 		ajStrAppendCountK(&sitestr, *claimchar, nameend-end);
2552 		ajDebug("showFillREFlat ajStrAppKI '%c' %d\n",
2553 			*claimchar, nameend-end);
2554 	    }
2555 
2556 	    /* cover binding site with '='s */
2557 	    for(i=base-start; i<base-start+ajStrGetLen(m->pat); i++)
2558 		ajStrPasteCountK(&sitestr, i, '=', 1);
2559 
2560 	    ajDebug("showFillREFlat ajStrReplaceK '=' %d..%d\n",
2561 		    base-start, i-1);
2562 
2563 	    /*
2564 	    **  I tried showing the pattern instead of '='s, but it looks
2565 	    **  awful - GWW 12 Jan 2000
2566 	    **      for(j=0, i=base-start; i<base-start+ajStrGetLen(m->pat);
2567 	    **           j++, i++)
2568 	    **          (ajStrGetPtr(sitestr)+i) = ajStrGetPtr(m->pat)[j];
2569 	    */
2570 
2571 	    /* put in cut sites */
2572 	    if(info->sense == 1)
2573 	    {				/* forward sense */
2574 		if(info->plasmid || !m->circ12)
2575 		{
2576 		    ajStrPasteCountK(&sitestr, (cut1-start-1), '>', 1);
2577 		    ajDebug("showFillREFlat ajStrReplaceK1 '>' %d\n",
2578 			    (cut1-start-1));
2579 		}
2580 
2581 		if(info->plasmid || !m->circ34)
2582 		{
2583 		    if(cut3)
2584 		    {
2585 			ajStrPasteCountK(&sitestr, (cut3-start-1), '>', 1);
2586 
2587 			ajDebug("showFillREFlat ajStrReplaceK3 '>' %d\n",
2588 				(cut3-start-1));
2589 		    }
2590 		}
2591 	    }
2592 	    else
2593 	    {				/* reverse sense */
2594 		if(info->plasmid || !m->circ12)
2595 		{
2596 		    ajStrPasteCountK(&sitestr, (cut2-start-1), '<', 1);
2597 		    ajDebug("showFillREFlat ajStrReplaceK2 '<' %d\n",
2598 			    (cut2-start-1));
2599 		}
2600 
2601 		if(info->plasmid || !m->circ34)
2602 		{
2603 		    if(cut4)
2604 		    {
2605 			ajStrPasteCountK(&sitestr, (cut4-start-1), '<', 1);
2606 			ajDebug("showFillREFlat ajStrReplaceK4 '<' %d\n",
2607 				(cut4-start-1));
2608 		    }
2609 		}
2610 	    }
2611 
2612 
2613 	    /* name string stuff */
2614 	    /* initial string of claimchar's */
2615 	    namestr = ajStrNew();
2616 	    ajStrAppendCountK(&namestr, *claimchar, end-start+1 );
2617 	    ajDebug("showFillREFlat ajStrAppKI name '%c' %d\n",
2618 		    *claimchar, end-start+1 );
2619 
2620 	    if(nameend > end)
2621 	    {
2622 		ajStrAppendCountK(&namestr, *claimchar, nameend-end);
2623 		ajDebug("showFillREFlat ajStrAppKI nameend '%c' %d\n",
2624 			*claimchar, nameend-end );
2625 	    }
2626 
2627 	    /* insert the name in the namestr */
2628 	    ajStrPasteS(&namestr, (base-start), m->cod);
2629 
2630 	    /* now chop up the name and site strings to fit in the line */
2631 
2632 	    /* is the feature completely within the line */
2633 	    if(start >= pos && end <= last)
2634 	    {
2635 		/*
2636 		 *  add on an extra couple of claim chars to make a space
2637 		 *  between adjacent matches
2638 		 */
2639 		ajStrAppendC(&sitestr, claimchar);
2640 		ajStrAppendC(&sitestr, claimchar);
2641 
2642 	    }
2643 	    else if(start < pos && end <= last)
2644 	    {
2645 		/* starts before the line. cut off the start */
2646 		ajStrKeepRange(&sitestr, pos-start, ajStrGetLen(sitestr)-1);
2647 
2648 		/*
2649 		**  add on an extra couple of claim chars to make a space
2650 		**  between adjacent matches
2651 		*/
2652 		ajStrAppendC(&sitestr, claimchar);
2653 		ajStrAppendC(&sitestr, claimchar);
2654 
2655 		/*
2656 		**  if the base position is not displayed, move the name to
2657 		**  the start
2658 		*/
2659 		if(base < pos)
2660 		{
2661 		    ajStrAssignS(&namestr, m->cod);
2662 		    ajStrAppendC(&namestr, claimchar);
2663 		    ajStrAppendC(&namestr, claimchar);
2664 
2665 		    /*
2666 		    **  add claim characters to end of namestring if
2667 		    **  sitestring is longer, and vice versa
2668 		    */
2669 		    if(ajStrGetLen(namestr) < ajStrGetLen(sitestr))
2670 			ajStrAppendCountK(&namestr, *claimchar,
2671 					  ajStrGetLen(sitestr)-
2672                                           ajStrGetLen(namestr));
2673 		    if(ajStrGetLen(namestr) > ajStrGetLen(sitestr))
2674 			ajStrAppendCountK(&sitestr, *claimchar,
2675 					  ajStrGetLen(namestr)-
2676                                           ajStrGetLen(sitestr));
2677 		}
2678 		else
2679 		    /*
2680 		    **  cut off the start of the name string to make it line
2681 		    **  up with the sitestr
2682 		    */
2683 		    ajStrKeepRange(&namestr, pos-start, ajStrGetLen(namestr)-1);
2684 
2685 		/* make it display from the start of the line */
2686 		start = pos;
2687 
2688 
2689 	    }
2690 	    else if(start >= pos && end > last)
2691 	    {
2692 		/* ends after the line. cut off the end */
2693 		ajStrKeepRange(&sitestr, 0, last - start);
2694 		/*
2695 		**  if the base position is not displayed, move the name
2696 		**  to the start
2697 		*/
2698 		if(base > last)
2699 		{
2700 		    ajStrAssignS(&namestr, m->cod);
2701 		    ajStrAppendC(&namestr, claimchar);
2702 		    ajStrAppendC(&namestr, claimchar);
2703 
2704 		    /*
2705 		    **  add claim characters to end of namestring if
2706 		    **  sitestring is longer, and vice versa
2707 		    */
2708 		    if(ajStrGetLen(namestr) < ajStrGetLen(sitestr))
2709 			ajStrAppendCountK(&namestr, *claimchar,
2710 					  ajStrGetLen(sitestr)-
2711                                           ajStrGetLen(namestr));
2712 		    if(ajStrGetLen(namestr) > ajStrGetLen(sitestr))
2713 			ajStrAppendCountK(&sitestr, *claimchar,
2714 					  ajStrGetLen(namestr)-
2715                                           ajStrGetLen(sitestr));
2716 		}
2717 
2718 		/* make it display to the end of the line */
2719 		end = last;
2720 
2721 
2722 	    }
2723 	    else if(start < pos && end > last)
2724 	    {
2725 		/* completely overlaps the line! cut off the start and end */
2726 		ajStrKeepRange(&sitestr, pos-start, last-start);
2727 
2728 		/*
2729 		**  if the base position is not displayed, move the name to
2730 		**  the start
2731 		*/
2732 		if(base < pos)
2733 		{
2734 		    ajStrAssignS(&namestr, m->cod);
2735 		    ajStrAppendC(&namestr, claimchar);
2736 		    ajStrAppendC(&namestr, claimchar);
2737 
2738 		    /*
2739 		    **  add claim characters to end of namestring if
2740 		    **  sitestring is longer, and vice versa
2741 		    */
2742 		    if(ajStrGetLen(namestr) < ajStrGetLen(sitestr))
2743 			ajStrAppendCountK(&namestr, *claimchar,
2744 					  ajStrGetLen(sitestr)-
2745                                           ajStrGetLen(namestr));
2746 		    if(ajStrGetLen(namestr) > ajStrGetLen(sitestr))
2747 			ajStrAppendCountK(&sitestr, *claimchar,
2748 					  ajStrGetLen(namestr)-
2749                                           ajStrGetLen(sitestr));
2750 		}
2751 		else
2752 		{
2753 		    /*
2754 		    **  cut off the start of the name string to make it line
2755 		    **  up with the sitestr
2756 		    */
2757 		    ajStrKeepRange(&namestr, pos-start,
2758 				    /* ...or should this be , */
2759 				    /* last-start); */
2760 				    ajStrGetLen(namestr)-1);
2761 		}
2762 
2763 		/* make it display from the start of the line */
2764 		start = pos;
2765 		end   = last;
2766 	    }
2767 	    else
2768 	    {
2769 		ajDebug("Shouldn't get to here!");
2770 		continue;
2771 	    }
2772 
2773 	    /* work up list of lines */
2774 	    freespace = ajFalse;
2775 
2776 	    /*
2777 	    **  potentially updating the nodes of linelist, so
2778 	    **  don't just iterate, use ajListstrPop and ajListstrPushApp
2779 	    **  to pop off the bottom and then push the altered node back on
2780 	    **  the top of the list
2781 	    */
2782 	    for(ln = (ajuint) ajListstrGetLength(linelist); ln>0; ln--)
2783 	    {
2784 		ajListstrPop(linelist, &line); /* get the site line */
2785 		ajListstrPop(linelist, &line2); /* get the name line */
2786 
2787 		/*
2788 		**  if not yet written the name in this set of
2789 		**  iterations, see if can be done now
2790 		*/
2791 		if(!freespace)
2792 		{
2793 		    if(showLineIsClear(&line, start-pos, end-pos))
2794 		    {
2795 			showOverPrint(&line, start-pos, sitestr);
2796 			showOverPrint(&line2, start-pos, namestr);
2797 			/* flag to show name written */
2798 			freespace = ajTrue;
2799 		    }
2800 		}
2801 
2802 		ajListstrPushAppend(linelist, line);
2803 		ajListstrPushAppend(linelist, line2);
2804                 line = NULL;
2805                 line2 = NULL;
2806 		/* end 'iteration' through lines */
2807 	    }
2808 
2809 	    /*
2810 	    **  if didn't find a clear region to print in, append two new
2811 	    **  strings and print in them
2812 	    */
2813 	    if(!freespace)
2814 	    {
2815 		line=ajStrNew();
2816 
2817 		/* fill with spaces */
2818 		ajStrAppendCountK(&line, ' ', width);
2819 		line2=ajStrNew();
2820 
2821 		/* fill with spaces */
2822 		ajStrAppendCountK(&line2, ' ', width);
2823 
2824 		showOverPrint(&line, start-pos, sitestr);
2825 		showOverPrint(&line2, start-pos, namestr);
2826 		ajListstrPushAppend(linelist, line);
2827 		ajListstrPushAppend(linelist, line2);
2828                 line = NULL;
2829                 line2 = NULL;
2830 	    }
2831 
2832 	    ajStrDel(&namestr);
2833 	    ajStrDel(&sitestr);
2834 	}
2835     }
2836 
2837     ajListIterDel(&miter);
2838 
2839 
2840     /*
2841     **  reverse the order of the lines if we are in the forward sense as then
2842     **  we get the most densely populated lines at the bottom closest to the
2843     **  sequence (and we get the names above the cut-sites)
2844     */
2845     if(info->sense == 1)
2846 	ajListstrReverse(linelist);
2847 
2848     /* iterate through the lines and print them */
2849     liter = ajListIterNewread(linelist);
2850 
2851     while((line = ajListIterGet(liter)) != NULL)
2852     {
2853 	/*
2854 	**  convert claim characters in the line to spaces as these were
2855 	**  used to stake a claim to the space
2856 	*/
2857 	ajStrExchangeSetCC(&line, claimchar, " ");
2858 
2859 	/*
2860 	**  remove trailing spaces - these can be very long in namestr when
2861 	**  the cut and recognition sites are widely separated and so many
2862 	**  claimchars have been appended
2863 	*/
2864 	ajStrTrimEndC(&line, " ");
2865 
2866 	showMargin(thys, lines);
2867 	ajListstrPushAppend(lines, line);
2868         line = NULL;
2869 	ajListstrPushAppend(lines, ajFmtStr("\n"));
2870     }
2871 
2872     ajListIterDel(&liter);
2873 
2874 
2875     while(ajListPop(linelist,&sajb));
2876 
2877     ajListstrFree(&linelist);
2878 
2879     return;
2880 }
2881 
2882 
2883 
2884 
2885 /* @funcstatic showFillFT *****************************************************
2886 **
2887 ** Add this line's worth of features to the lines list
2888 ** NB. the 'source' feature is always ignored
2889 **
2890 ** @param [r] thys [const EmbPShow] Show sequence object
2891 ** @param [u] lines [AjPList] list of lines to add to
2892 ** @param [r] info [const EmbPShowFT] data on how to display the features
2893 ** @param [r] pos [ajuint] current printing position in the sequence
2894 ** @param [r] last [ajuint] last printing position in the sequence
2895 ** @return [void]
2896 **
2897 ** @release 1.0.0
2898 ** @@
2899 ******************************************************************************/
2900 
showFillFT(const EmbPShow thys,AjPList lines,const EmbPShowFT info,ajuint pos,ajuint last)2901 static void showFillFT(const EmbPShow thys,
2902 		       AjPList lines, const EmbPShowFT info,
2903 		       ajuint pos, ajuint last)
2904 {
2905 
2906 
2907     AjIList iter  = NULL;
2908     AjPFeature gf = NULL;
2909 
2910     AjPStr line      = NULL;
2911     AjPStr line2     = NULL;
2912     AjPList linelist = NULL;	/* list of lines to fill */
2913     ajuint start;
2914     ajuint end;
2915     ajuint namestart;
2916     ajuint nameend;		/* start and end position of namestr */
2917     AjIList liter;		/* iterator for linelist */
2918     AjPStr namestr = NULL;	/* name of feature to insert into line */
2919     AjPStr linestr = NULL;	/* line graphics to insert */
2920     const char *claimchar = "*";   /* char used to stake a claim to */
2921 				   /* that position in the string */
2922     AjBool freespace;		/* flag for found a free space to
2923 				   print in */
2924     ajuint ln;
2925     void* sajb = NULL;
2926 
2927     ajuint width;
2928 
2929     width = last - pos + 1;
2930 
2931     ajDebug("showFillFT\n");
2932     linelist = ajListstrNew();
2933 
2934     /*
2935     **  if feat is NULL then there are no features associated with this
2936     **  sequence
2937     */
2938     if(!info->feat)
2939 	return;
2940 
2941 
2942     /* iterate through the features */
2943     if(info->feat->Features)
2944     {
2945 	iter = ajListIterNewread(info->feat->Features) ;
2946 
2947 	while(!ajListIterDone(iter))
2948 	{
2949 	    gf = ajListIterGet(iter) ;
2950 
2951             /* ignore remote IDs */
2952             if(!ajFeatIsLocal(gf))
2953 		continue;
2954 
2955             /* don't output the 'source' feature */
2956 	    if(!ajStrCmpC(ajFeatGetType(gf), "source"))
2957 		continue;
2958 
2959 	    /*
2960 	    ** check that the feature is within the line to display (NB.
2961 	    ** Working in human coordinates here: 1 to SeqLength,
2962 	    ** not 0 to SeqLength-1)
2963 	    */
2964 	    if(pos >= ajFeatGetEnd(gf) ||
2965 	       last <= ajFeatGetStart(gf))
2966 		continue;
2967 
2968 	    /* prepare name string */
2969 	    namestr = ajStrNew();
2970 	    ajStrAssignS(&namestr,  ajFeatGetType(gf));
2971 
2972 	    /* add tags to namestr*/
2973 	    showAddTags(&namestr, gf, ajTrue);
2974 
2975 	    /*
2976 	    **  note the start and end positions of the name and line
2977 	    **  graphics
2978 	    */
2979 	    start = (ajFeatGetStart(gf)-1<pos) ?
2980 		pos : ajFeatGetStart(gf)-1;
2981 	    end   = (ajFeatGetEnd(gf)-1>last) ?
2982 		last : ajFeatGetEnd(gf)-1;
2983 
2984 	    /* print the name starting with the line */
2985 	    namestart = start;
2986 	    nameend   =  start + ajStrGetLen(namestr)-1;
2987 
2988 	    /* shift long namestr back if longer than the line when printed */
2989 	    if(nameend > last+thys->margin)
2990 	    {
2991 		if(ajStrGetLen(namestr) > end-pos+1)
2992 		{
2993 		    namestart = pos;
2994 		    nameend = pos + ajStrGetLen(namestr) -1;
2995 
2996 		    /*
2997 		    **  it is shifted back to the start of the display line
2998 		    **  is it still longer than the line? truncate it
2999 		    */
3000 		    if(nameend > thys->width-1+thys->margin)
3001 		    {
3002 			ajStrTruncateLen(&namestr, thys->width-1+thys->margin);
3003 			nameend = pos+thys->width-1+thys->margin;
3004 		    }
3005 		}
3006 		else
3007 		{
3008 		    namestart = end - ajStrGetLen(namestr)+1;
3009 		    nameend = namestart + ajStrGetLen(namestr)-1;
3010 		}
3011 	    }
3012 
3013 	    /*
3014 	    **  add on any claim characters required to stake a claim to
3015 	    **  positions used by the line graphics
3016 	    */
3017 	    if(end > nameend)
3018 	    {
3019 		ajStrAppendCountK(&namestr, *claimchar, end-nameend);
3020 		nameend = end;
3021 	    }
3022 
3023 	    /*
3024 	    **  add on a couple more claim characters to space out the
3025 	    **  features
3026 	    */
3027 	    ajStrAppendCountK(&namestr, *claimchar, 2);
3028 	    nameend += 2;
3029 
3030 	    /* prepare line string */
3031 	    /* initial string of '='s */
3032 	    linestr = ajStrNew();
3033 	    ajStrAppendCountK(&linestr, '=', end-start+1 );
3034 
3035 	    /* put in end position characters */
3036 	    if(ajFeatGetStart(gf)-1>=pos)
3037 		ajStrPasteCountK(&linestr,0, '|', 1);
3038 
3039 	    if(ajFeatGetEnd(gf)-1<=last)
3040 		ajStrPasteCountK(&linestr, (end-start), '|', 1);
3041 
3042 
3043 	    /* work up list of lines */
3044 	    freespace = ajFalse;
3045 
3046 	    /*
3047 	    **  iterate through list of existing lines to find no overlap
3048 	    **  with existing lines we will be potentially updating the
3049 	    **  nodes of linelist, so don't just iterate, use ajListstrPop
3050 	    **  and ajListstrPushApp to pop off the bottom and then push
3051 	    **  the altered node back on the top of the list
3052 	    */
3053 	    for(ln = (ajuint) ajListstrGetLength(linelist); ln>0; ln--)
3054 	    {
3055 		/* get the linestr line */
3056 		ajListstrPop(linelist, &line);
3057 		/* get the namestr line */
3058 		ajListstrPop(linelist, &line2);
3059 
3060 		/*
3061 		**  if not yet written the name in this set of
3062 		**  iterations, see if it can be done now
3063 		*/
3064 		if(!freespace)
3065 		{
3066 		    /* if name space is clear, write namestr and sitestr */
3067 		    if(showLineIsClear(&line2, start-pos, end-pos) &&
3068 			showLineIsClear(&line2, namestart-pos, nameend-pos))
3069 		    {
3070 			showOverPrint(&line, start-pos, linestr);
3071 			showOverPrint(&line2, namestart-pos, namestr);
3072 			/* flag to show name written */
3073 			freespace = ajTrue;
3074 		    }
3075 		}
3076 
3077 		ajListstrPushAppend(linelist, line);
3078 		ajListstrPushAppend(linelist, line2);
3079                 line = NULL;
3080                 line2 = NULL;
3081 		/* end 'iteration' through lines */
3082 	    }
3083 
3084 	    /*
3085 	    **  if didn't find a clear region to print in, append two new
3086 	    **  strings and print in them
3087 	    */
3088 	    if(!freespace)
3089 	    {
3090 		line=ajStrNew();
3091 		/* fill with spaces */
3092 		ajStrAppendCountK(&line, ' ', width);
3093 		line2=ajStrNew();
3094 		/* fill with spaces */
3095 		ajStrAppendCountK(&line2, ' ', width);
3096 
3097 		showOverPrint(&line, start-pos, linestr);
3098 		showOverPrint(&line2, namestart-pos, namestr);
3099 		ajListstrPushAppend(linelist, line);
3100 		ajListstrPushAppend(linelist, line2);
3101                 line = NULL;
3102                 line2 = NULL;
3103 	    }
3104 
3105 	    ajStrDel(&namestr);
3106 	    ajStrDel(&linestr);
3107 	}
3108 	ajListIterDel(&iter);
3109     }
3110 
3111     /* iterate through the lines and print them */
3112     liter = ajListIterNewread(linelist);
3113     while((line = ajListIterGet(liter)) != NULL)
3114     {
3115 	/*
3116 	** convert claim characters in the line to spaces as these were
3117 	** used to stake a claim to the space
3118 	*/
3119 	ajStrExchangeSetCC(&line, claimchar, " ");
3120 
3121 	/* remove trailing spaces - these can be very long */
3122 	ajStrTrimEndC(&line, " ");
3123 
3124 	/*
3125 	** output to the lines list
3126 	** variable width margin at left
3127 	*/
3128 	showMargin(thys, lines);
3129 
3130 	/*
3131 	** with optional number in it
3132 	** put the translation line on the output list
3133 	*/
3134 	ajListstrPushAppend(lines, line);
3135         line = NULL;
3136 	/* end output line */
3137 	ajListstrPushAppend(lines, ajFmtStr("\n"));
3138     }
3139 
3140     ajListIterDel(&liter);
3141 
3142 
3143     while(ajListPop(linelist,&sajb));
3144 
3145     ajListstrFree(&linelist);
3146 
3147     return;
3148 }
3149 
3150 
3151 
3152 
3153 /* @funcstatic showFillNote ***************************************************
3154 **
3155 ** Add this line's worth of user annotation to the lines list
3156 **
3157 ** @param [r] thys [const EmbPShow] Show sequence object
3158 ** @param [u] lines [AjPList] list of lines to add to
3159 ** @param [r] info [const EmbPShowNote] data on how to display the annotation
3160 ** @param [r] pos [ajuint] current printing position in the sequence
3161 ** @param [r] last [ajuint] last printing position in the sequence
3162 ** @return [void]
3163 **
3164 ** @release 2.1.0
3165 ** @@
3166 ******************************************************************************/
showFillNote(const EmbPShow thys,AjPList lines,const EmbPShowNote info,ajuint pos,ajuint last)3167 static void showFillNote(const EmbPShow thys,
3168 			 AjPList lines, const EmbPShowNote info,
3169 			  ajuint pos, ajuint last)
3170 {
3171 
3172     AjPStr line  = NULL;
3173     AjPStr line2 = NULL;
3174     AjPList linelist = NULL;	/* list of lines to fill */
3175     ajuint start;
3176     ajuint end;			/* start and end position of linestr */
3177     ajuint namestart;
3178     ajuint nameend;		/* start and end position of namestr */
3179     AjIList liter;		/* iterator for linelist */
3180     AjPStr namestr = NULL;	/* name of feature to insert into line */
3181     AjPStr linestr = NULL;	/* line graphics to insert */
3182     const char *claimchar = "*";   /* char used to stake a claim to */
3183 				   /* that position in the string */
3184     AjBool freespace;		/* flag for found a free space to print in */
3185     ajint ln;
3186     void* sajb = NULL;
3187 
3188     ajuint count;		/* count of annotation region */
3189     ajuint rstart;
3190     ajuint rend;			/* region start and end */
3191     ajuint width;
3192 
3193     width = last - pos + 1;
3194 
3195     ajDebug("showFillFT\n");
3196     linelist = ajListstrNew();
3197 
3198     /* count through the annotation regions */
3199     if(info->regions && ajRangeGetSize(info->regions))
3200     {
3201 	for(count = 0; count < ajRangeGetSize(info->regions); count++)
3202 	{
3203             ajRangeElementGetValues(info->regions, count, &rstart, &rend);
3204 
3205 	    /*
3206 	    ** check that the region is within the line to display
3207 	    */
3208 	    if(pos >= rend || last <= rstart)
3209 		continue;
3210 
3211 	    /* get annotation string */
3212             ajRangeElementGetText(info->regions, count, &namestr);
3213 
3214 	    /*
3215 	    **  note the start and end positions of the name and line
3216 	    **  graphics
3217 	    */
3218 	    start = (rstart-1<pos) ? pos : rstart-1;
3219 	    end   = (rend-1>last) ? last :
3220 		rend-1;
3221 
3222 	    /* print the name starting with the line */
3223 	    namestart = start;
3224 	    nameend   = start + ajStrGetLen(namestr)-1;
3225 
3226 	    /* shift long namestr back if longer than the line when printed */
3227 	    if(nameend >last+thys->margin)
3228 	    {
3229 		if(ajStrGetLen(namestr) > end-pos+1)
3230 		{
3231 		    namestart = pos;
3232 		    nameend = pos + ajStrGetLen(namestr) -1;
3233 
3234 		    /*
3235 		    **  it is shifted back to the start of the display line
3236 		    **  is it still longer than the line? truncate it
3237 		    */
3238 		    if(nameend > width-1+thys->margin)
3239 		    {
3240 			ajStrTruncateLen(&namestr, width-1+thys->margin);
3241 			nameend = last+thys->margin;
3242 		    }
3243 		}
3244 		else
3245 		{
3246 		    namestart = end - ajStrGetLen(namestr)+1;
3247 		    nameend = namestart + ajStrGetLen(namestr)-1;
3248 		}
3249 	    }
3250 
3251 	    /*
3252 	    **  add on any claim characters required to stake a claim to
3253 	    **  positions used by the line graphics
3254 	    */
3255 	    if(end > nameend)
3256 	    {
3257 		ajStrAppendCountK(&namestr, *claimchar, end-nameend);
3258 		nameend = end;
3259 	    }
3260 
3261 	    /*
3262 	    **  add on a couple more claim characters to space out the
3263 	    **  features
3264 	    */
3265 	    ajStrAppendCountK(&namestr, *claimchar, 2);
3266 	    nameend += 2;
3267 
3268 	    /*
3269 	    ** prepare line string
3270 	    ** initial string of '-'s
3271 	    */
3272 	    linestr = ajStrNew();
3273 	    ajStrAppendCountK(&linestr, '-', end-start+1 );
3274 
3275 	    /* put in end position characters */
3276 	    if(rstart-1>=pos)
3277 		ajStrPasteCountK(&linestr, 0, '|', 1);
3278 
3279 	    if(rend-1<=last)
3280 		ajStrPasteCountK(&linestr, (end-start), '|', 1);
3281 
3282 	    /* work up list of lines */
3283 	    freespace = ajFalse;
3284 
3285 	    /*
3286 	    **  iterate through list of existing lines to find no overlap
3287 	    **  with existing lines we will be potentially updating the
3288 	    **  nodes of linelist, so don't just iterate, use ajListstrPop
3289 	    **  and ajListstrPushApp to pop off the bottom and then push
3290 	    **  the altered node back on the top of the list
3291 	    */
3292 	    for(ln = (ajuint) ajListstrGetLength(linelist); ln>0; ln--)
3293 	    {
3294 		/* linestr line */
3295 		ajListstrPop(linelist, &line);
3296 		/* namestr line */
3297 		ajListstrPop(linelist, &line2);
3298 
3299 		/*
3300 		 *  if not yet written the name in this set of
3301 		 *  iterations, see if it can be done now
3302 		 */
3303 		if(!freespace)
3304 		{
3305 		    /* if name space is clear, write namestr and sitestr */
3306 		    if(showLineIsClear(&line2, start-pos, end-pos) &&
3307 			showLineIsClear(&line2, namestart-pos, nameend-pos))
3308 		    {
3309 			showOverPrint(&line, start-pos, linestr);
3310 			showOverPrint(&line2, namestart-pos, namestr);
3311 
3312 			/* flag to show name written */
3313 			freespace = ajTrue;
3314 		    }
3315 		}
3316 
3317 		ajListstrPushAppend(linelist, line);
3318 		ajListstrPushAppend(linelist, line2);
3319                 line = NULL;
3320                 line2 = NULL;
3321 		/* end 'iteration' through lines */
3322 	    }
3323 
3324 	    /*
3325 	    **  if we didn't find a clear region to print in, append two new
3326 	    **  strings and print in them
3327 	    */
3328 	    if(!freespace)
3329 	    {
3330 		line=ajStrNew();
3331 		/* fill with spaces */
3332 		ajStrAppendCountK(&line, ' ', width);
3333 		line2=ajStrNew();
3334 
3335 		/* fill with spaces */
3336 		ajStrAppendCountK(&line2, ' ', width);
3337 
3338 		showOverPrint(&line, start-pos, linestr);
3339 
3340 		showOverPrint(&line2, namestart-pos, namestr);
3341 		ajListstrPushAppend(linelist, line);
3342 		ajListstrPushAppend(linelist, line2);
3343                 line = NULL;
3344                 line2 = NULL;
3345 	    }
3346 
3347 	    ajStrDel(&namestr);
3348 	    ajStrDel(&linestr);
3349 	}
3350     }
3351 
3352     /* iterate through the lines and print them */
3353     liter = ajListIterNewread(linelist);
3354 
3355     while((line = ajListIterGet(liter)) != NULL)
3356     {
3357 	/*  convert claim characters in the line to spaces as these were
3358 	**  used to stake a claim to the space
3359 	*/
3360 	ajStrExchangeSetCC(&line, claimchar, " ");
3361 
3362 	/* remove trailing spaces - these can be very long */
3363 	ajStrTrimEndC(&line, " ");
3364 
3365 	/*
3366 	** output to the lines list
3367 	** variable width margin at left
3368 	*/
3369 	showMargin(thys, lines);
3370 
3371 	/*
3372 	** with optional number in it
3373 	** put the translation line on the output list
3374 	*/
3375 	ajListstrPushAppend(lines, line);
3376         line = NULL;
3377 	/* end output line */
3378 	ajListstrPushAppend(lines, ajFmtStr("\n"));
3379     }
3380     ajListIterDel(&liter);
3381 
3382 
3383     while(ajListPop(linelist,&sajb));
3384 
3385     ajListstrFree(&linelist);
3386 
3387     return;
3388 }
3389 
3390 
3391 
3392 
3393 /* @funcstatic showOverPrint **************************************************
3394 **
3395 ** Overwrite (appending if necessary) a portion of a string with another
3396 **
3397 ** @param [u] target [AjPStr *] target string to overwrite
3398 ** @param [r] start [ajint] start position in target to begin overwriting at
3399 ** @param [u] insert [AjPStr] string to overwrite with
3400 ** @return [void]
3401 **
3402 ** @release 1.0.0
3403 ** @@
3404 ******************************************************************************/
3405 
showOverPrint(AjPStr * target,ajint start,AjPStr insert)3406 static void showOverPrint(AjPStr *target, ajint start, AjPStr insert)
3407 {
3408     /*
3409     ** if start position of insert is less than length of target, pad it out
3410     ** with space characters to get the required length
3411     */
3412 
3413     if(ajStrGetLen(*target) < start+ajStrGetLen(insert))
3414 	ajStrAppendCountK(target, ' ',
3415 		   start+ajStrGetLen(insert) - ajStrGetLen(*target));
3416 
3417     /* overwrite the remaining characters */
3418     ajStrPasteS(target, start, insert);
3419 
3420     return;
3421 }
3422 
3423 
3424 
3425 
3426 /* @funcstatic showLineIsClear ************************************************
3427 **
3428 ** Checks that a section of a string is clear to print in (only has blanks in)
3429 **
3430 ** @param [u] line [AjPStr *] target string to check
3431 ** @param [r] start [ajint] start position in target to begin checking at
3432 ** @param [r] end [ajint] end position in target to check
3433 ** @return [AjBool] ajTrue on success
3434 **
3435 ** @release 1.0.0
3436 ** @@
3437 ******************************************************************************/
3438 
showLineIsClear(AjPStr * line,ajint start,ajint end)3439 static AjBool showLineIsClear(AjPStr *line, ajint start, ajint end)
3440 {
3441     ajint i;
3442     ajint len;
3443 
3444     len = ajStrGetLen(*line)-1;
3445 
3446     if(len < end)
3447 	ajStrAppendCountK(line, ' ', end-len);
3448 
3449     for(i=start; i<=end; i++)
3450 	if(ajStrGetCharPos(*line,i) != ' ')
3451 	    return ajFalse;
3452 
3453     return ajTrue;
3454 }
3455 
3456 
3457 
3458 
3459 /* @funcstatic showAddTags ****************************************************
3460 **
3461 ** writes feature tags to the tagsout string
3462 **
3463 ** @param [w] tagsout [AjPStr*] tags out string
3464 ** @param [r] feat [const AjPFeature] Feature to be processed
3465 ** @param [r] values [AjBool] display values of tags (currently ignored)
3466 **
3467 ** @return [void]
3468 **
3469 ** @release 2.0.0
3470 ** @@
3471 ******************************************************************************/
3472 
showAddTags(AjPStr * tagsout,const AjPFeature feat,AjBool values)3473 static void showAddTags(AjPStr *tagsout, const AjPFeature feat, AjBool values)
3474 {
3475 
3476     AjPStr tagnam = NULL;
3477     AjPStr tagval = NULL;
3478     AjIList titer;
3479 
3480     /*
3481     ** iterate through the tags and test for match to patterns
3482     */
3483 
3484     (void) values;			/* make it used */
3485 
3486     tagval = ajStrNew();
3487     tagnam = ajStrNew();
3488 
3489     titer = ajFeatTagIter(feat);
3490 
3491     /* don't display the translation tag - it is far too long */
3492     while(ajFeatTagval(titer, &tagnam, &tagval))
3493 	if(ajStrCmpC(tagnam, "translation"))
3494 	{
3495 	    if(ajStrGetLen(tagval))
3496 		ajFmtPrintAppS(tagsout, " %S=\"%S\"", tagnam, tagval);
3497 	    else
3498 		ajFmtPrintAppS(tagsout, " %S", tagnam);
3499 	}
3500 
3501     ajListIterDel(&titer);
3502 
3503     ajStrDel(&tagval);
3504     ajStrDel(&tagnam);
3505 
3506     return;
3507 }
3508