/*
 *                    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.das;

import java.util.*;
import java.net.*;
import java.io.*;

import org.biojava.bio.*;
import org.biojava.utils.*;
import org.biojava.bio.seq.*;
import org.biojava.bio.seq.io.*;
import org.biojava.bio.symbol.*;

import org.apache.xerces.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import org.w3c.dom.*;

/**
 * FeatureHolder reflecting features provided by a DAS annotation
 * server.
 *
 * @since 1.1
 * @author Thomas Down
 */

class DASFeatureSet implements FeatureHolder {
    private SimpleFeatureHolder realFeatures;
    private final Sequence refSequence;
    private final URL dataSource;
    private final String sourceID;
    private final String dataSourceString;

    DASFeatureSet(Sequence seq, URL ds, String id)
        throws BioException
    {
	refSequence = seq;
	dataSource = ds;
	sourceID = id;
	dataSourceString = dataSource.toString();
    }

    protected FeatureHolder getFeatures() {
	if (realFeatures != null)
	    return realFeatures;

	try {
	    realFeatures = new SimpleFeatureHolder();

	    
	    SeqIOListener listener = new SeqIOAdapter() {
		    private List featureStack = new ArrayList();
		    private Feature stackTop = null;

		    public void startFeature(Feature.Template temp) 
		        throws ParseException
		    {
			if (temp instanceof ComponentFeature.Template) {
			    // I'm not convinced there's an easy, safe, way to say we don't
			    // want these server side, so we'll elide them here instead.
			    // We push a null onto the stack so that we don't get confused
			    // over endFeature().

			    featureStack.add(null);
			} else {
			    try {
				Feature f = null;
				if (temp.annotation == Annotation.EMPTY_ANNOTATION) {
				    temp.annotation = new SimpleAnnotation();
				}
				temp.annotation.setProperty(DASSequence.PROPERTY_ANNOTATIONSERVER, dataSourceString);

				if (stackTop == null) {
				    f = ((RealizingFeatureHolder) refSequence).realizeFeature(refSequence, temp);
				    realFeatures.addFeature(f);
				} else {
				    f = stackTop.createFeature(temp);
				}
				
				featureStack.add(f);
				stackTop = f;
			    } catch (Exception ex) {
				throw new ParseException(ex, "Couldn't realize feature in DAS");
			    }
			}
		    }

		    public void endFeature()
		        throws ParseException
		    {
			if (featureStack.size() < 1) {
			    throw new BioError("Missmatched endFeature()");
			} else {
			    featureStack.remove(featureStack.size() - 1);
			    int pos = featureStack.size() - 1;
			    stackTop = null;
			    while (stackTop == null && pos >= 0) {
				stackTop = (Feature) featureStack.get(pos--);
			    }
			}
		    }
		} ;

	    boolean useXFF = DASCapabilities.checkCapable(new URL(dataSource, ".."),
							  DASCapabilities.CAPABILITY_FEATURETABLE,
							  DASCapabilities.CAPABILITY_FEATURETABLE_XFF);

	    if (useXFF) {
		URL fURL = new URL(dataSource, "features?encoding=xff;ref=" + sourceID);
		DASXFFParser.INSTANCE.parseURL(fURL, listener);
	    } else {
		URL fURL = new URL(dataSource, "features?ref=" + sourceID);
		DASGFFParser.INSTANCE.parseURL(fURL, listener);
	    }
	   
	} catch (IOException ex) {
	    throw new BioError(ex, "Error connecting to DAS server");
	} catch (ParseException ex) {
	    throw new BioError(ex, "Error parsing feature table");
	} catch (BioException ex) {
	    throw new BioError(ex);
	}

	return realFeatures;
    }

    public Iterator features() {
	return getFeatures().features();
    }

    public FeatureHolder filter(FeatureFilter ff, boolean recurse) {
	return getFeatures().filter(ff, recurse);
    }
    
    public int countFeatures() {
	return getFeatures().countFeatures();
    }
    
    public Feature createFeature(Feature.Template temp) 
        throws ChangeVetoException
    {
	throw new ChangeVetoException("Can't create features on DAS sequences.");
    }

    public void removeFeature(Feature f) 
        throws ChangeVetoException
    {
	throw new ChangeVetoException("Can't remove features from DAS sequences.");
    }

    // 
    // Changeable stuff (which we're not, fortunately)
    //

    public void addChangeListener(ChangeListener cl) {}
    public void addChangeListener(ChangeListener cl, ChangeType ct) {}
    public void removeChangeListener(ChangeListener cl) {}
    public void removeChangeListener(ChangeListener cl, ChangeType ct) {}
}

@@ -2472,22 +2472,16 @@
 taSource
-String
 );%0A%0A%09%09%09%09

Put URL objects into annotation rather than Strings.