package org.geotools.complex;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import net.opengis.wfs.FeatureCollectionType;
import net.opengis.wfs.WfsFactory;

import org.geotools.data.Query;
import org.geotools.data.property.PropertyDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.LenientFeatureFactoryImpl;
import org.geotools.feature.type.FeatureTypeFactoryImpl;
import org.geotools.wfs.v1_1.WFS;
import org.geotools.wfs.v1_1.WFSConfiguration;
import org.geotools.xml.Encoder;
import org.geotools.xsd.ApplicationSchemaConfiguration;
import org.geotools.xsd.ApplicationSchemaXSD;
import org.opengis.feature.ComplexAttribute;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.type.AttributeType;
import org.opengis.feature.type.ComplexType;
import org.opengis.feature.type.FeatureType;

import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.Point;

public class ComplexGMLBuilder {

    private static final String TARGET_SCHEMA = "http://xyz.com";

    public static void main(String[] args) throws Exception {
        // get the bugsites
        PropertyDataStore pds = new PropertyDataStore(new File(
                "./src/main/resources/org/geotools/complex"), TARGET_SCHEMA);
        Query q = new Query();
        q.setMaxFeatures(2);
        SimpleFeatureCollection bugsites = pds.getFeatureSource("bugsites").getFeatures(q);

        // build the target complex schema
        TypeBuilder tb = new TypeBuilder(new FeatureTypeFactoryImpl());
        tb.setNamespaceURI(TARGET_SCHEMA);
        // ... start by building the various attribute types
        AttributeType featuresType = tb.name("features").bind(FeatureCollection.class).attribute();
        AttributeType name = tb.name("name").bind(String.class).attribute();
        AttributeType geometry = tb.name("geometry").bind(MultiPoint.class).attribute();
        AttributeType count = tb.name("count").bind(Integer.class).attribute();
        // ... now build the complex feature
        tb.addAttribute("name", name);
        tb.addAttribute("count", count);
        tb.addAttribute("geometry", geometry);
        tb.addAttribute("features", featuresType);
        tb.setName("SummaryFeatureType");
        FeatureType summarySchema = tb.feature();

        System.out.println(summarySchema);

        // build the complex feature
        AttributeBuilder ab = new AttributeBuilder(new LenientFeatureFactoryImpl());
        ab.setType(summarySchema);
        ab.setNamespaceURI(TARGET_SCHEMA);
        // .. build the complex feature
        ab.add("bugsitesSummary", "name");
        ab.add(bugsites.size(), "count");
        ab.add(summarizeGeometry(bugsites), "geometry");
        ab.add(bugsites, "features");
        
        Feature result = (Feature) ab.build("SummaryFeature.1");

        // build the feature collection
        FeatureCollection fc = new ListComplexFeatureCollection(summarySchema);
        fc.add(result);
        
        // build the wfs container
        FeatureCollectionType fct = WfsFactory.eINSTANCE.createFeatureCollectionType();
        fct.getFeature().add(fc);

        ApplicationSchemaXSD xsd = new ApplicationSchemaXSD("xyz", "http://xyz.com", new File(
                "src/main/resources/org/geotools/complex/complex.xsd"), WFS.getInstance());
        Encoder encoder = new Encoder(new ApplicationSchemaConfiguration(xsd,
                new WFSConfiguration()));
        encoder.setIndentSize(2);
        encoder.setNamespaceAware(true);
        encoder.encode(fct, WFS.FeatureCollection, System.out);
    }

    static MultiPoint summarizeGeometry(SimpleFeatureCollection bugsites) {
        List<Point> points = new ArrayList<Point>();
        GeometryFactory gf = null;
        SimpleFeatureIterator fi = bugsites.features();
        while(fi.hasNext()) {
            SimpleFeature f = fi.next();
            Point p = (Point) f.getDefaultGeometry();
            if(p != null) {
                points.add(p);
                gf = p.getFactory();
            }
        }
        fi.close();
        if(points.size() > 0) {
            return gf.createMultiPoint((Point[]) points.toArray(new Point[points.size()]));
        } else {
            return null;
        }
    }

    

}
