001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.bio.seq.io.agave;
022import java.io.IOException;
023import java.io.PrintStream;
024import java.io.PrintWriter;
025import java.util.Iterator;
026
027import org.biojava.bio.Annotatable;
028import org.biojava.bio.seq.ComponentFeature;
029import org.biojava.bio.seq.Feature;
030import org.biojava.bio.seq.FeatureHolder;
031import org.biojava.bio.seq.Sequence;
032import org.biojava.bio.seq.SimpleAssembly;
033import org.biojava.bio.seq.StrandedFeature;
034import org.biojava.bio.seq.impl.SimpleSequence;
035
036/**
037 * Writes Sequence into AGAVE XML document.  The AGAVE
038 * format is defined in agave.dtd which can be downloaded
039 * from http://www.agavexml.org.
040 *
041 * @author Hanning Ni
042 * @author Brian King
043 */
044public class AgaveWriter
045{
046    /**
047     * Implements indenting for elements.
048     * @author Brian King
049     */
050    protected class Indent
051    {
052        /** Base indent    */
053        protected String mIndent = new String(INDENT);
054
055        /**
056         * Add a level of indentation
057        */
058        public void
059        indent()
060        {
061            mIndent += INDENT;
062        }
063
064        /**
065         * Remove a level of indentation
066         *
067         */
068        public void
069        unIndent()
070        {
071            int len  = mIndent.length();
072            int iLen = INDENT.length();
073            if(len >= iLen)
074            {
075                mIndent = mIndent.substring(0, len - iLen);
076            }
077        }
078
079        /**
080         * Return the current indent
081         *
082         */
083        public String
084        toString()
085        {
086            return mIndent;
087        }
088    }
089
090   /** use a two space indent */
091    public static final String INDENT = "  ";
092
093    /** Write to XML document    */
094    protected PrintWriter mOut;
095
096    /** indent */
097    protected Indent mIndent;
098
099    /** writes PCDATA replacing XML characters with escape entities */
100    protected PCDATAFilterWriter mFilter;
101
102    /**
103     * The AnnotationMap to use for getting
104     * AGAVE XML attributes from a Sequence Annotation.
105     */
106    protected AGAVEAnnotFilter mAnnotFilter;
107
108    /** write DOCTYPE if true */
109    protected boolean mWriteDocType = true;
110
111    /**
112     * Default constructor uses generic annotation to attribute mapping.
113     *
114     */
115    public AgaveWriter()
116    {
117        mAnnotFilter = SimpleAnnotFilter.SIMPLE_ANNOT_FILTER_FACTORY.getInstance();
118        mIndent = new Indent();
119    }
120
121    /**
122     * Construct with data source specific annotation to attribute
123     * mapping.
124     *
125     */
126    public AgaveWriter(AGAVEAnnotFilter filter)
127    {
128        mAnnotFilter = filter;
129        mIndent = new Indent();
130    }
131
132    /**
133     * Set flag that determines if XML DOCTYPE is written
134     * or not.  Default is true.
135     *
136     */
137    public void
138    setWriteDocType(boolean writeDocType)
139    {
140        mWriteDocType = writeDocType;
141    }
142
143     /**
144     * Write sequence into AGAVE XML format.
145     * @param seq maybe the  or simple sequence
146     * <pre>
147     * if annotation of seq has chromosome information , generate <chromosome> tag
148     * if seq is SimpleAssembly, generate <contig> tag
149     * otherwise, generate <bio_sequence> tag
150     * currently  each top-level sequence is wrapped into seperated sciobj xml file
151     * </pre>
152     */
153    public void writeSequence(Sequence seq, PrintStream os)
154           throws IOException
155    {
156        mOut = new PrintWriter(os);
157        mFilter = new PCDATAFilterWriter(mOut);
158
159        mOut.println("<?xml version=\"1.0\"?>");
160        if (mWriteDocType)
161        {
162            mOut.println("<!DOCTYPE sciobj SYSTEM \"agave.dtd\">");
163        }
164        writeHeader();
165        write(seq);
166        writeFooter();
167    }
168
169    /**
170     * Write &lt;sciobj&gt;
171     *
172     */
173    protected void
174    writeHeader()
175    {
176        mOut.println("<sciobj version=\"2\">");
177    }
178
179    /**
180     * Write &lt;/sciobj&gt;
181     */
182    protected void
183    writeFooter()
184    {
185        mOut.println("</sciobj>");
186        mOut.flush();
187    }
188
189    /**
190     *
191     * Writing Sequence.
192     * @param seq is simple sequence or simple assembly
193     *
194     */
195    protected void
196    write(Sequence seq) throws IOException
197    {
198        String chrom_num = mAnnotFilter.getChromNum( seq.getAnnotation() );
199        if( chrom_num != null )
200        {
201            mIndent.indent();
202            mOut.print(mIndent);
203            mOut.println("<chromosome number=\"" + chrom_num + "\">");
204            writeContig((Annotatable) seq );
205            mOut.print(mIndent);
206            mOut.println("</chromosome>");
207            mIndent.unIndent();
208        }
209        else
210        {
211            if( seq instanceof SimpleAssembly)
212            {
213               writeContig(  (Annotatable)seq ) ;
214            }
215            else
216            {
217                writeBioSequence((Annotatable)seq);
218            }
219        }
220    }
221
222    /**
223     *
224     *
225     */
226    protected void
227    writeContig(Annotatable seq ) throws IOException
228    {
229    /**
230    <!ELEMENT contig (db_id , view? , note? , fragment_order* , unordered_fragments? ,  assembly? ,
231                  sequence? , sequence_map* ,  map_location* )>
232    <!ATTLIST contig length NMTOKEN  #REQUIRED >
233    */
234        mIndent.indent();
235        mOut.print(mIndent);
236        mOut.print("<contig");
237
238
239        mOut.print(" length=\"");
240        mOut.print( ((Sequence)seq).length() );
241        mOut.print('"');
242        mOut.println(">");
243
244        writeDbId(seq);
245        writeNote(seq);
246        writeAssembly(seq);
247        writeDNA(seq) ;
248        writeMapLocation(seq) ;
249
250
251        mOut.print(mIndent);
252        mOut.println("</contig>");
253        mIndent.unIndent();
254
255    }
256
257    /**
258     *
259     *
260     */
261    protected void
262    writeAssembly(Annotatable seq) throws IOException
263    {
264        /** <!ELEMENT assembly (bio_sequence | fragment_order)+ > */
265        mIndent.indent();
266        mOut.print(mIndent);
267        mOut.println("<assembly>");
268        if(seq instanceof SimpleSequence)
269            write((Sequence) seq ) ;
270        else if( seq instanceof SimpleAssembly)
271        {
272            for (Iterator i  =((Sequence) seq).features(); i.hasNext(); )
273            {
274                Feature subf = (Feature)i.next();
275                if( subf instanceof ComponentFeature)
276                    writeBioSequence((Annotatable)  ((ComponentFeature)subf).getComponentSequence() ) ;
277            }
278        }
279
280        mOut.print(mIndent);
281        mOut.println("</assembly>");
282        mIndent.unIndent();
283    }
284
285    /**
286     *
287     *
288     */
289    protected void
290    writeBioSequence(Annotatable seq ) throws IOException
291    {
292        String s;
293        mIndent.indent();
294        mOut.print(mIndent);
295        mOut.print("<bio_sequence");
296
297
298        // write attributes
299        //
300        if( seq instanceof Sequence)
301        {
302            mOut.print(" seq_length=\"");
303            mOut.print( ((Sequence)seq).length() );
304            mOut.print('"');
305        }
306
307        s = mAnnotFilter.getOrganism(seq.getAnnotation());
308        if (s != null)
309        {
310            mOut.print(" organism_name=\"");
311            mFilter.write(s);
312            mOut.print('"');
313        }
314
315        s = mAnnotFilter.getMolType( seq.getAnnotation() );
316        if (s == null && (seq instanceof Sequence)) {
317            s = ((Sequence) seq).getAlphabet().getName();
318        }
319        if (s != null)
320        {
321            mOut.print(" molecule_type=\"");
322            mFilter.write(s);
323            mOut.print('"');
324        }
325
326        s = mAnnotFilter.getElementId(seq.getAnnotation());
327        if (s == null && (seq instanceof Sequence)) {
328            s = ((Sequence) seq).getName();
329        }
330        if (s != null)
331        {
332            mOut.print(" element_id=\"");
333            mFilter.write(s);
334            mOut.print('"');
335        }
336
337        s = mAnnotFilter.getSequenceId(seq.getAnnotation());
338        if (s != null)
339        {
340            mOut.print(" sequence_id=\"");
341            mFilter.write(s);
342            mOut.print('"');
343        }
344
345        s = mAnnotFilter.getTaxonId(seq.getAnnotation());
346        if (s != null)
347        {
348            mOut.print(" taxon_id=\"");
349            mFilter.write(s);
350            mOut.print('"');
351        }
352
353        s = mAnnotFilter.getCloneId(seq.getAnnotation());
354        if (s != null)
355        {
356            mOut.print(" clone_id=\"");
357            mFilter.write(s);
358            mOut.print('"');
359        }
360
361        s = mAnnotFilter.getCloneLibrary(seq.getAnnotation());
362        if (s != null)
363        {
364            mOut.print(" clone_library=\"");
365            mFilter.write(s);
366            mOut.print('"');
367        }
368
369        s = mAnnotFilter.getChromosome(seq.getAnnotation());
370        if (s != null)
371        {
372            mOut.print(" chromosome=\"");
373            mFilter.write(s);
374            mOut.print('"');
375        }
376
377        s = mAnnotFilter.getMapPosition(seq.getAnnotation());
378        if (s != null)
379        {
380            mOut.print(" map_position=\"");
381            mFilter.write(s);
382            mOut.print('"');
383        }
384
385        s = mAnnotFilter.getEcNumber(seq.getAnnotation());
386        if (s != null)
387        {
388            mOut.print(" ec_number=\"");
389            mFilter.write(s);
390            mOut.print('"');
391        }
392
393        s = mAnnotFilter.getCreateDate(seq.getAnnotation());
394        if (s != null)
395        {
396            mOut.print(" update_date=\"");
397            mFilter.write(s);
398            mOut.print('"');
399        }
400
401
402        mOut.println(">");  // close bio_sequence tag
403
404        // write content
405        writeDbId(seq) ;
406        writeDNA( seq ) ;
407        writeAltIds( seq ) ;
408        writeXrefs( seq ) ;
409        writeSequenceMap2(seq);   // THOMASD hacked this....
410        writeMapLocation(seq) ;
411        writeClassification(seq);
412
413        mIndent.unIndent();
414        mOut.print(mIndent);
415        mOut.println("</bio_sequence>");
416    }
417
418    /**
419     * group sequence_map by getSource()
420     */
421    protected void
422    writeSequenceMap(Annotatable seq) throws IOException
423    {
424        for (Iterator i  = ((FeatureHolder)seq).features(); i.hasNext();)
425        {
426            Feature f = (Feature) i.next();
427            String type = f.getSource();
428            if( type.equalsIgnoreCase("classification") )
429                continue ;
430            // writeFeature( f );
431            writeSequenceMap2( f );
432         }
433    }
434
435    /**
436     *
437     *
438     */
439    protected void
440    writeClassification(Annotatable seq) throws IOException
441    {
442        for (Iterator i  = ((FeatureHolder)seq).features(); i.hasNext();)
443        {
444            Feature f = (Feature) i.next();
445            String type = f.getSource();
446            if( type.equalsIgnoreCase("classification") )
447            {
448                writeClassification2(f) ;
449            }
450        }
451     }
452
453    /**
454     *
455     *
456     */
457     private void
458     writeClassification2(Annotatable f) throws IOException
459     {
460     /**
461     <!ELEMENT classification (description? , id_alias* , evidence? )>
462     <!ATTLIST classification system      CDATA  #REQUIRED
463                         id        CDATA  #REQUIRED
464                         type        CDATA  #REQUIRED
465                         assigned_by CDATA  #IMPLIED >
466     */
467        mOut.print(mIndent);
468        mOut.print("<classification");
469        mIndent.indent();
470
471        // write attributes
472        //
473        String s = mAnnotFilter.getClassifySystem( f.getAnnotation() ); ;
474        if(s != null)
475        {
476            mOut.print(" system=\"");
477            mFilter.write(s);
478            mOut.print('"');
479        }
480        s = mAnnotFilter.getClassifyId( f.getAnnotation() ); ;
481        if(s != null)
482        {
483            mOut.print(" id=\"");
484            mFilter.write(s);
485            mOut.print('"');
486        }
487        s = mAnnotFilter.getClassifyType( f.getAnnotation() ); ;
488        if(s != null)
489        {
490            mOut.print(" type=\"");
491            mFilter.write(s);
492            mOut.print('"');
493        }
494        mOut.println(">");  // close map tag
495
496        writeDescription( f ) ;
497        writeIdAlias( f ) ;
498        writeEvidence( f ) ;
499
500        mOut.print(mIndent);
501        mOut.println("</classification>");
502        mIndent.unIndent();
503     }
504
505     /**
506      *
507      *
508      */
509     private void
510     writeIdAlias(Annotatable f) throws IOException
511     {
512       AGAVEIdAlias[] annots =  mAnnotFilter.getIdAlias(f.getAnnotation());
513       if( annots != null )
514       {
515           mIndent.indent();
516           for(int i = 0 ; i < annots.length; i++)
517              mOut.print( annots[i].toString(mIndent.toString(), INDENT ));
518           mIndent.unIndent();
519       }
520     }
521
522     /**
523     *  Write SequenceMap XML
524     *
525     */
526    protected void
527    writeSequenceMap2(Annotatable f) throws IOException
528    {
529/*
530<!ELEMENT sequence_map  (note? , computation? , annotations? )>
531<!ATTLIST sequence_map label        CDATA #IMPLIED >
532*/
533        mIndent.indent();
534        mOut.print(mIndent);
535        mOut.print("<sequence_map");
536
537
538        // write attributes
539        //
540        String label = mAnnotFilter.getLabel(f.getAnnotation()) ;
541        if(label != null)
542        {
543            mOut.print(" label=\"");
544            mFilter.write(label);
545            mOut.print('"');
546        }
547        mOut.println(">");  // close map tag
548
549        // write content
550        //
551
552        //write note
553        //
554        writeNote(f) ;
555
556        //ignore write computation
557
558        writeAnnotations((FeatureHolder) f);
559
560        mOut.print(mIndent);
561        mOut.println("</sequence_map>");
562        mIndent.unIndent();
563
564    }
565
566    /**
567     *
568     *
569     */
570    protected void writeAnnotations(FeatureHolder f) throws IOException   // changed to FeatureHolder THOMASD
571    {
572     //write annotation
573        //    <!ELEMENT annotations       (seq_feature | gene | comp_result )+ >
574        mIndent.indent();
575        mOut.print(mIndent);
576        mOut.println("<annotations>");
577
578  /*      for (Iterator i  = f.features(); i.hasNext(); )
579        {
580                Feature feature = (Feature) i.next();
581                if( feature.getSource().equalsIgnoreCase("annotations") )
582                {
583                    f = feature  ;
584                    break;
585                }
586        } */
587        for (Iterator i  = f.features(); i.hasNext(); )
588        {
589                Feature feature = (Feature) i.next();
590                String type = feature.getSource() ;
591                if( type == null || type.equalsIgnoreCase( "seq_feature" ) )
592                   writeSeqFeature(feature);
593                else if( type.equalsIgnoreCase( "gene") )
594                   writeGene( feature);
595                else { //default mapping to comp_result
596                    // writeCompResult( feature);
597                   writeSeqFeature(feature);  // THOMASD
598                }
599        }
600        mOut.print(mIndent);
601        mOut.println("</annotations>");
602        mIndent.unIndent();
603    }
604
605    /**
606     *
607     *
608     */
609   protected void
610   writeGene(Annotatable f) throws IOException
611   {
612   /**
613   <!ELEMENT gene (classification* , note? , seq_location , xrefs? ,
614                evidence? , qualifier* , seq_feature* , related_annot* ,
615                transcript*)>
616   <!ATTLIST gene  element_id   ID     #IMPLIED
617                label        CDATA  #IMPLIED >
618   **/
619        mIndent.indent();
620        mOut.print(mIndent);
621        mOut.print("<gene");
622
623        String s ;
624
625        s = mAnnotFilter.getElementId( f.getAnnotation() );
626        if (s != null)
627        {
628            mOut.print(" element_id=\"");
629            mFilter.write(s);
630            mOut.print('"');
631        }
632
633        s = mAnnotFilter.getLabel( f.getAnnotation() );
634        if (s != null)
635        {
636            mOut.print(" label=\"");
637            mFilter.write(s);
638            mOut.print('"');
639        }
640
641
642        mOut.println('>');
643
644        // write content
645        writeNote(f) ;
646        writeSeqLocation( f ) ;
647        writeXrefs( f ) ;
648        writeEvidence(f) ;
649        writeProperty(f,  AGAVEProperty.QUALIFIER ) ;
650        writeSubSeqFeature( f ) ;
651        writeRelatedAnnot( f ) ;
652        writeTranscript( f ) ;
653
654
655       mOut.print(mIndent);
656       mOut.println("</gene>");
657       mIndent.unIndent();
658   }
659
660   /**
661    *
662    *
663    */
664   protected void
665   writeTranscript( Annotatable f) throws IOException
666   {
667      /**
668       * <!ELEMENT transcript (exons , cds? , mrna? , predicted_protein?)>
669       */
670      for (Iterator i  = ((FeatureHolder)f).features(); i.hasNext(); )
671      {
672          Feature subf = (Feature)i.next();
673          if( subf.getSource().equalsIgnoreCase("transcript") )
674              writeTranscript2(subf);
675      }
676   }
677
678   /**
679    *
680    *
681    */
682   private void
683   writeTranscript2(Annotatable f) throws IOException
684   {
685         mIndent.indent();
686         mOut.print(mIndent);
687         mOut.println("<transcript>");
688         writeExons(f);
689         for (Iterator i  = ((FeatureHolder)f).features(); i.hasNext(); )
690         {
691            Feature subf = (Feature)i.next();
692            String type = subf.getSource() ;
693            if( type.equalsIgnoreCase("cds") )
694               writeCds(subf);
695            else if( type.equalsIgnoreCase("mrna") )
696               writeMrna(subf);
697            else if( type.equalsIgnoreCase("predicted_protein") )
698               writePredictedProtein(subf);
699
700         }
701         mOut.print(mIndent);
702         mOut.println("</transcript>");
703         mIndent.unIndent();
704   }
705
706   /**
707    *
708    *
709    */
710   private void
711   writeExons(Annotatable f) throws IOException
712   {
713       String[] ids =  mAnnotFilter.getExonIds(f.getAnnotation());
714       if( ids != null )
715       {
716           mIndent.indent();
717           mOut.print(mIndent);
718           mOut.println("<exons>");
719           for(int i = 0 ; i < ids.length; i++)
720           {
721               mOut.println(mIndent + INDENT + "<element_id id=\"" + ids[i] + "\"/>");
722           }
723           mOut.print(mIndent);
724           mOut.println("</exons>") ;
725           mIndent.unIndent();
726       }
727   }
728
729   /**
730    *
731    *
732    */
733   private void writeCds(Annotatable f) throws IOException
734   {
735       mIndent.indent();
736       mOut.print(mIndent);
737       mOut.println("<cds>");
738       writeBioSequence( f) ;
739       mOut.print(mIndent);
740       mOut.println("</cds>");
741       mIndent.unIndent();
742   }
743
744   /**
745    *
746    *
747    */
748   private void writeMrna(Annotatable f) throws IOException
749   {
750       mIndent.indent();
751       mOut.print(mIndent);
752       mOut.println("<mrna>");
753       writeBioSequence( f) ;
754       mOut.print(mIndent);
755       mOut.println("</mrna>");
756       mIndent.unIndent();
757   }
758
759   /**
760    *
761    *
762    */
763   private void writePredictedProtein(Annotatable f) throws IOException
764   {
765       mIndent.indent();
766       mOut.print(mIndent);
767       mOut.println("<predicted_protein>");
768       writeBioSequence( f) ;
769       mOut.print(mIndent);
770       mOut.println("</predicted_protein>");
771       mIndent.unIndent();
772   }
773
774    /**
775     *  Write SeqFeature XML
776     */
777    protected void
778    writeSeqFeature( Annotatable f) throws IOException
779    {
780/*
781<!ELEMENT seq_feature  (classification* , note? , seq_location , xrefs? ,
782                        evidence? , qualifier* ,  seq_feature* , related_annot*)>
783<!ATTLIST seq_feature element_id   ID     #IMPLIED
784                      feature_type CDATA  #REQUIRED
785                      label        CDATA  #IMPLIED >
786*/
787        mIndent.indent();
788        mOut.print(mIndent);
789        mOut.print("<seq_feature");
790
791
792        // write attributes
793        //
794        String s = mAnnotFilter.getFeatureType( f.getAnnotation() );
795        if (s == null) {  // THOMASD
796            s = ((Feature) f).getType();
797        }
798        mOut.print(" feature_type=\"");
799        mFilter.write( s == null? "default" : s );
800        mOut.print('"');
801
802        s = mAnnotFilter.getElementId( f.getAnnotation() );
803        if (s != null)
804        {
805            mOut.print(" element_id=\"");
806            mFilter.write(s);
807            mOut.print('"');
808        }
809
810        s = mAnnotFilter.getLabel( f.getAnnotation() );
811        if (s != null)
812        {
813            mOut.print(" label=\"");
814            mFilter.write(s);
815            mOut.print('"');
816        }
817
818
819        mOut.println('>');
820
821        // write content
822        writeNote(f) ;
823        writeSeqLocation( f ) ;
824        writeXrefs( f ) ;
825        writeEvidence(f) ;
826        writeProperty(f,  AGAVEProperty.QUALIFIER ) ;
827        writeSubSeqFeature( f ) ;
828        writeRelatedAnnot( f ) ;
829
830
831       mOut.print(mIndent);
832       mOut.println("</seq_feature>");
833       mIndent.unIndent();
834
835    }
836
837    /**
838     *
839     *
840     */
841    private void
842    writeRelatedAnnot( Annotatable f)
843    {
844       AGAVERelatedAnnot[] annots =  mAnnotFilter.getRelatedAnnot(f.getAnnotation());
845       if( annots != null )
846       {
847           for(int i = 0 ; i < annots.length; i++)
848              mOut.print( annots[i].toString(mIndent + INDENT, INDENT));
849       }
850    }
851
852    /**
853     *
854     *
855     */
856    private void
857    writeEvidence(Annotatable f) throws IOException
858    {
859        for (Iterator i  = ((FeatureHolder)f).features(); i.hasNext(); )
860        {
861            Feature subf = (Feature)i.next();
862            if( subf.getSource().equalsIgnoreCase("evidence") )
863                writeEvidence2(subf);
864        }
865    }
866
867    /**
868     *
869     *
870     */
871    private void
872    writeEvidence2(Annotatable f) throws IOException
873    {
874        //element_ids
875        writeElementIds( f ) ;
876        //comp_result
877        for (Iterator i  = ((FeatureHolder)f).features(); i.hasNext(); )
878        {
879            Feature subf = (Feature)i.next();
880            writeCompResult(  subf );
881        }
882    }
883
884    /**
885     *
886     *
887     */
888    private void
889    writeElementIds(Annotatable f) throws IOException
890    {
891       String[] ids =  mAnnotFilter.getElementIds(f.getAnnotation());
892       if( ids != null )
893       {
894           for(int i = 0 ; i < ids.length; i++)
895           {
896                mOut.println(mIndent + INDENT + "<element_id id=\"" + ids[i] + "\"/>");
897           }
898       }
899    }
900
901    /*
902    <!ELEMENT comp_result  (note? , match_desc? , match_align? , query_region? ,
903                        match_region? , result_property* , result_group* ,
904                        related_annot*)>
905    <!ATTLIST comp_result  element_id           ID       #IMPLIED
906                       result_id            NMTOKEN  #IMPLIED
907                       group_order          NMTOKEN  #IMPLIED
908                       result_type          CDATA    #REQUIRED
909                       feature_type         CDATA    #IMPLIED
910                       on_complement_strand  (true | false )  'false'
911                       confidence           NMTOKEN  #IMPLIED
912                       align_length         NMTOKEN  #IMPLIED
913                       align_units          (bp | AA) #IMPLIED >
914    */
915    protected
916    void writeCompResult(Annotatable f) throws IOException
917    {
918        mIndent.indent();
919        mOut.print(mIndent);
920        mOut.print("<comp_result");
921
922
923        // write attributes
924        //
925        String s = mAnnotFilter.getResultType( f.getAnnotation() );
926        mOut.print(" result_type=\"");
927        mFilter.write( s == null? "default" : s );
928        mOut.print('"');
929
930        s = mAnnotFilter.getElementId( f.getAnnotation() );
931        if (s != null)
932        {
933            mOut.print(" element_id=\"");
934            mFilter.write(s);
935            mOut.print('"');
936        }
937
938        String strand = "false";
939        if( f instanceof StrandedFeature )
940        {
941            char mark = ((StrandedFeature)f).getStrand().getToken() ;
942            if ( mark == '-' )
943                strand= "true" ;
944        }
945        mOut.print(" on_complement_strand=\"");
946        mFilter.write(strand);
947        mOut.print('"');
948
949        s = mAnnotFilter.getGroupOrder( f.getAnnotation() );
950        if (s != null)
951        {
952            mOut.print(" group_order=\"");
953            mFilter.write(s);
954            mOut.print('"');
955        }
956
957        s = mAnnotFilter.getFeatureType( f.getAnnotation() );
958        if (s != null)
959        {
960            mOut.print(" feature_type=\"");
961            mFilter.write(s);
962            mOut.print('"');
963        }
964
965        s = mAnnotFilter.getConfidence( f.getAnnotation() );
966        if (s != null)
967        {
968            mOut.print(" confidence=\"");
969            mFilter.write(s);
970            mOut.print('"');
971        }
972
973        s = mAnnotFilter.getAlignLength( f.getAnnotation() );
974        if (s != null)
975        {
976            mOut.print(" align_length=\"");
977            mFilter.write(s);
978            mOut.print('"');
979        }
980        s = mAnnotFilter.getAlignUnits( f.getAnnotation() );
981        if (s != null)
982        {
983            mOut.print(" align_units=\"");
984            mFilter.write(s);
985            mOut.print('"');
986        }
987        mOut.println(">");
988
989       writeNote( f ) ;
990       writeMatchDesc( f ) ;
991       writeMatchAlign( f ) ;
992       writeQueryRegion( f ) ;
993       writeMatchRegion( f ) ;
994       writeProperty( f, AGAVEProperty.RESULT_PROPERTY) ;
995       writeResultGroup( f )  ;
996       writeRelatedAnnot(f);
997
998       mOut.print(mIndent);
999       mOut.println("</comp_result>");
1000       mIndent.unIndent();
1001    }
1002
1003    /**
1004     *   <!ELEMENT result_group  (comp_result+ )>
1005     *   <!ATTLIST result_group  group_order NMTOKEN  '0' >
1006     */
1007    private void
1008    writeResultGroup(Annotatable f) throws IOException
1009    {
1010        Iterator i = ((FeatureHolder)f).features() ;
1011        if( i == null ) //void
1012            return ;
1013        while( i.hasNext() )
1014        {
1015            Feature subf = (Feature)i.next();
1016            String type = subf.getSource();
1017            if( type != null && type.equalsIgnoreCase("result_group") )
1018            {
1019                mIndent.indent();
1020                mOut.println( mIndent + "<result_group>");
1021                for(Iterator k = subf.features(); k.hasNext();)
1022                    writeCompResult( (Feature)k.next() ) ;
1023                mOut.println(mIndent + "</result_group>");
1024                mIndent.unIndent();
1025            }
1026            else
1027            {
1028                 mIndent.indent();
1029                 mOut.println(mIndent + "<result_group>");
1030                 writeCompResult( subf ) ;
1031                 mOut.println(mIndent + "</result_group>");
1032                 mIndent.unIndent();
1033            }
1034        }
1035    }
1036
1037    /**
1038     *
1039     *
1040     */
1041    private void
1042    writeQueryRegion(Annotatable f) throws IOException
1043    {
1044        AGAVEQueryRegion s =   mAnnotFilter.getQueryRegion( f.getAnnotation() );
1045        if( s != null )
1046        {
1047            mIndent.indent();
1048            mOut.println( s.toString(mIndent.toString()  , INDENT ) );
1049            mIndent.unIndent();
1050        }
1051    }
1052
1053    /**
1054     *
1055     *
1056     */
1057    private void
1058    writeMatchRegion(Annotatable f) throws IOException
1059    {
1060        AGAVEMatchRegion s =   mAnnotFilter.getMatchRegion( f.getAnnotation() );
1061        if( s != null )
1062        {
1063            mIndent.indent();
1064            mOut.println( s.toString(mIndent.toString()  , INDENT ) );
1065            mIndent.unIndent();
1066        }
1067    }
1068
1069    /**
1070     *
1071     *
1072     */
1073    private void
1074    writeMatchAlign(Annotatable f) throws IOException
1075    {
1076        String s =   mAnnotFilter.getMatchAlign( f.getAnnotation() );
1077        if( s != null )
1078        {
1079            if (s.startsWith("<match_align") )
1080            {
1081                mFilter.write(s);
1082             }else{
1083                mIndent.indent();
1084                mOut.print(mIndent);
1085                mOut.print("<match_align>");
1086                mFilter.write(s);
1087                mOut.println("</match_align>");
1088                mIndent.unIndent();
1089             }
1090         }
1091    }
1092
1093    /**
1094     *
1095     *
1096     */
1097   private void
1098   writeMatchDesc(Annotatable f) throws IOException
1099    {
1100        String s =   mAnnotFilter.getMatchDesc( f.getAnnotation() );
1101        if( s != null )
1102        {
1103            if (s.startsWith("<match_desc") )
1104            {
1105                mFilter.write(s);
1106             }else{
1107                mIndent.indent();
1108                mOut.print(mIndent);
1109                mOut.print("<match_desc>");
1110                mFilter.write(s);
1111                mOut.println("</match_desc>");
1112                mIndent.unIndent();
1113             }
1114         }
1115    }
1116
1117   /**
1118    *
1119    *
1120    */
1121    private void
1122    writeSubSeqFeature(Annotatable f ) throws IOException
1123    {
1124        for (Iterator i  = ((FeatureHolder)f).features(); i.hasNext(); )
1125        {
1126            Feature subf = (Feature)i.next();
1127            //if the feature is not declared as <evidence>
1128            //treated as seq_feature
1129            if( subf.getSource().equalsIgnoreCase("evidence") )
1130                continue ;
1131           if( subf.getSource().equalsIgnoreCase("transcript") )
1132                continue ;
1133            writeSeqFeature( subf);
1134        }
1135    }
1136
1137    /**
1138     *
1139     *
1140     */
1141    private void
1142    writeSeqLocation( Annotatable f) throws IOException
1143    {
1144        int min = ((Feature)f).getLocation().getMin();
1145        int max = ((Feature)f).getLocation().getMax();
1146        boolean on_complement_strand  = false;
1147        if( f instanceof StrandedFeature)
1148        {
1149            int type =  ((StrandedFeature)f).getStrand().getValue() ;
1150            if( type == 1 )
1151                on_complement_strand = false ;
1152            else if( type == -1 )
1153                on_complement_strand = true ;
1154        }
1155        mIndent.indent();
1156        mOut.print(mIndent);
1157        mOut.print("<seq_location");
1158        mOut.print(" least_start=\"");
1159        mOut.print(min);
1160        mOut.print('"');
1161
1162        mOut.print(" greatest_end=\"");
1163        mOut.print(max);
1164        mOut.print('"');
1165
1166        if( f instanceof StrandedFeature)
1167        {
1168           mOut.print(" on_complement_strand=\"");
1169           mOut.print(on_complement_strand ? "true" : "false");
1170           mOut.print('"');
1171        }
1172        mOut.print(">");
1173
1174        mOut.print(min + ".." + max);
1175        mOut.println("</seq_location>");
1176        mIndent.unIndent();
1177    }
1178
1179    /**
1180     *
1181     *
1182     */
1183    private void
1184    writeDNA(Annotatable seq) throws IOException
1185    {
1186       if( seq instanceof Sequence)
1187       {
1188           int i = ((Sequence)seq).length();
1189           if (i > 0)
1190          {
1191              mIndent.indent();
1192              mOut.print(mIndent);
1193              mOut.print("<sequence>");
1194              int j ;
1195              for (j = 0 ; j < i / 80; j ++)
1196              {
1197               mOut.print(((Sequence)seq).subList(80 * j + 1, 80 * (j+1)).seqString() + "\n");
1198              }
1199
1200              mOut.print(((Sequence)seq).subList(80 * j + 1, i ).seqString());
1201              mOut.println("</sequence>");
1202              mIndent.unIndent();
1203           }
1204        }
1205    }
1206
1207    /**
1208     *
1209     *
1210     */
1211    private void writeXrefs(Annotatable f)
1212    {
1213       AGAVEXrefs[] xrefs =  mAnnotFilter.getXrefs(f.getAnnotation());
1214       if( xrefs != null )
1215       {
1216           mIndent.indent();
1217           for(int i = 0 ; i < xrefs.length; i++)
1218              mOut.print( xrefs[i].toString(mIndent.toString(), INDENT));
1219           mIndent.unIndent();
1220       }
1221    }
1222
1223    /**
1224     *
1225     *
1226     */
1227    private void
1228    writeAltIds(Annotatable f) throws IOException
1229    {
1230       AGAVEDbId[] db_id =  mAnnotFilter.getAltIds(f.getAnnotation());
1231       if( db_id!= null )
1232       {
1233           mIndent.indent();
1234           mOut.println(mIndent + "<alt_ids>");
1235           mIndent.indent();
1236           for(int i = 0 ; i < db_id.length; i++)
1237              mOut.print( db_id[i].toString(mIndent.toString(), INDENT));
1238           mIndent.unIndent();
1239           mOut.println(mIndent + "</alt_ids>");
1240           mIndent.unIndent();
1241       }
1242    }
1243
1244    /**
1245     *
1246     *
1247     */
1248    private void
1249    writeProperty(Annotatable f, String type)
1250    {
1251        AGAVEProperty[] aps =  mAnnotFilter.getProperty( f.getAnnotation(),type) ;
1252        if( aps != null )
1253        {
1254            mIndent.indent();
1255            for( int index  = 0 ; index < aps.length; index++)
1256                mOut.print( aps[index].toString(mIndent.toString(), INDENT));
1257            mIndent.unIndent();
1258        }
1259    }
1260
1261    /**
1262     *
1263     *
1264     */
1265    private void
1266    writeMapLocation(Annotatable f) throws IOException
1267    {
1268       AGAVEMapLocation[] mls =  mAnnotFilter.getMapLocation(f.getAnnotation());
1269       if( mls != null  )
1270       {
1271           mIndent.indent();
1272           for(int i = 0 ; i < mls.length; i++)
1273              mOut.print( mls[i].toString(mIndent.toString(),INDENT));
1274           mIndent.unIndent();
1275       }
1276    }
1277
1278    /**
1279     *
1280     *
1281     */
1282    private void
1283    writeDbId(Annotatable f) throws IOException
1284    {
1285        AGAVEDbId db_id = (AGAVEDbId)mAnnotFilter.getDbId(f.getAnnotation());
1286        if( db_id!= null )
1287        {
1288            mIndent.indent();
1289            mOut.println( db_id.toString(mIndent.toString(), INDENT) );
1290            mIndent.unIndent();
1291        }
1292    }
1293
1294    /**
1295     *
1296     *
1297     */
1298    private void
1299    writeDescription( Annotatable f) throws IOException
1300    {
1301        String s =   mAnnotFilter.getDescription( f.getAnnotation() );
1302        if( s != null )
1303        {
1304            if (s.startsWith("<description") )
1305            {
1306                mFilter.write(s);
1307             }else{
1308                mIndent.indent();
1309                mOut.print(mIndent);
1310                mOut.print("<description>");
1311                mFilter.write(s);
1312                mOut.println("</description>");
1313                mIndent.unIndent();
1314             }
1315         }
1316    }
1317
1318    /**
1319     *
1320     *
1321     */
1322    private void
1323    writeNote( Annotatable f) throws IOException
1324    {
1325        String note = mAnnotFilter.getNote(f.getAnnotation());
1326        if( note!= null )
1327        {
1328            if (note.startsWith("<note"))
1329            {
1330                mFilter.write(note);
1331            }
1332            else
1333            {
1334                mIndent.indent();
1335                mOut.print(mIndent);
1336                mOut.print("<note>");
1337                mFilter.write(note);
1338                mOut.println("</note>");
1339                mIndent.unIndent();
1340            }
1341        }
1342    }
1343}
1344