/*
 *                    BioJava development code
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  If you do not have a copy,
 * see:
 *
 *      http://www.gnu.org/copyleft/lesser.html
 *
 * Copyright for this code is held jointly by the individual
 * authors.  These should be listed in @author doc comments.
 *
 * For more information on the BioJava project and its aims,
 * or to join the biojava-l mailing list, visit the home page
 * at:
 *
 *      http://www.biojava.org/
 *
 */

package org.biojava.bio.program.sax.blastxml;

import org.biojava.bio.seq.io.game.ElementRecognizer;
import org.biojava.utils.stax.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

/**
 * This class parses NCBI Blast XML output.
 *
 * @author David Huen
 */
public class BlastXMLParser
    extends StAXFeatureHandler
{
    boolean firstTime = true;

    // constructor
    public BlastXMLParser()
    {
        // this is the base element class
        this.staxenv = this;
//        System.out.println("staxenv " + staxenv);
        // just set a DefaultHandler: does nothing worthwhile.
        this.listener = new DefaultHandler();
    }

    /**
     * sets the ContentHandler for this object
     */
    public void setContentHandler(org.xml.sax.ContentHandler listener)
    {
        this.listener = listener;
    }

    /**
     * we override the superclass startElement method so we can determine the
     * the start tag type and use it to set up delegation for the superclass.
     */
    public void startElement(
            String nsURI,
            String localName,
            String qName,
            Attributes attrs,
            DelegationManager dm)
        throws SAXException
    {
//        System.out.println("localName is " + localName);
        if (firstTime) {
            // what kind of tag do we have?
            if (localName.equals("BlastOutput")) {
                // this is a well-formed XML document from NCBI BLAST
                // pertaining to one search result
                super.addHandler(
                    new ElementRecognizer.ByLocalName("BlastOutput"),
                    new StAXHandlerFactory() {
                        public StAXContentHandler getHandler(StAXFeatureHandler staxenv) {
                            return new BlastOutputHandler(staxenv);
                        }
                    }
                );
            }
            else if (localName.equals("blast_aggregate")) {
                // this is my phony aggregate document that exists to
                // legitimise otherwise ill-formed output from NCBI Blast
                super.addHandler(new ElementRecognizer.ByLocalName("blast_aggregate"),
                    new StAXHandlerFactory() {
                        public StAXContentHandler getHandler(StAXFeatureHandler staxenv) {
                            return new BlastAggregator(staxenv);
                        }
                    }
                );
            }
            else {
                throw new SAXException("illegal element " + localName);
            }

            firstTime = false;

            // setup the root element of the output
            AttributesImpl bldscAttrs = new AttributesImpl();
            bldscAttrs.addAttribute("", "xmlns", "xmlns", CDATA, "");
            bldscAttrs.addAttribute(biojavaUri, "biojava", "xmlns:biojava", CDATA, "http://www.biojava.org");
            listener.startElement(biojavaUri, "BlastLikeDataSetCollection", biojavaUri + ":BlastLikeDataSetCollection", bldscAttrs);
        }

        // now invoke delegation
//        super.startElement(nsURI, localName, qName, attrs, dm);

        level++;

        // perform delegation
        // we must delegate only on features that are directly attached.
        // if I do not check that that's so, any element of a kind I delegate
        // on will be detected any depth within unrecognized tags.
        if (level == 1) {
//        System.out.println("StaxFeaturehandler.startElement starting. localName: " + localName + " " + level);
            for (int i = handlers.size() - 1; i >= 0; --i) {
                Binding b = (Binding) handlers.get(i);
                if (b.recognizer.filterStartElement(nsURI, localName, qName, attrs)) {
                    dm.delegate(b.handlerFactory.getHandler(this));
                    return;
                }
            }
        }

        // call the element specific handler now.
        // remember that if we we have a delegation failure we pass here too!
        if (level == 1) {
            startElementHandler(nsURI, localName, qName, attrs);
        }
    }

    public void endElementHandler(
            String nsURI,
            String localName,
            String qName,
            StAXContentHandler handler)
             throws SAXException
    {
        listener.endElement(biojavaUri, "BlastLikeDataSetCollection", biojavaUri + ":BlastLikeDataSetCollection");
    }
}

@@ -826,24 +826,1274 @@
 L output.%0A *
+ %3Cp%3E%0A * It has two modes:-%0A * i) single output document mode: this takes a document%0A * containing a single BlastOutput element and parses it.%0A * This is generated when a single query is searched against%0A * a sequence database.%0A * %3Cp%3E%0A * ii) multiple query document mode: unfortunately, NCBI%0A * BLAST concatenates the results of multiple searches in%0A * one file.  This leads to an ill-formed document that violates%0A * every XML format known to the human race and other nearby %0A * civilisations.  This parser will take a bowdlerised version of%0A * this output that is wrapped in a blast_aggregate element.%0A * %3Cp%3E%0A * The massaged form is generated by stripping the XML element and%0A * DOCTYPE elements and wrapping all the classes in a single%0A * blast_aggregate element.  In Linux, this can be done with:-%0A * %3Cpre%3E%0A * #!/bin/sh%0A * # Converts a Blast XML output to something vaguely well-formed%0A * # for parsing.%0A * # Use: blast_aggregate %3CXML output%3E %3Ceditted file%3E%0A *%0A * # strips all &lt;?xml&gt; and &lt;!DOCTYPE&gt; tags%0A * # encapsulates the multiple &lt;BlastOutput&gt; elements into &lt;blast_aggregator&gt;%0A *%0A * sed '/&gt;?xml/d' $1 %7C sed '/&lt;!DOCTYPE/d' %7C sed '1i%5C%0A * &lt;blast_aggregator&gt;%0A * $a%5C%0A * &lt;/blast_aggregator&gt;' %3E $2%0A *%3C/pre%3E%0A
 %0A * @author 

update javadocs