package org.opentripplanner.analyst;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.opentripplanner.analyst.pointset.PropertyMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ResultSet implements Serializable{

    private static final long serialVersionUID = -6723127825189535112L;

    private static final Logger LOG = LoggerFactory.getLogger(ResultSet.class);

    public String id;
    public Map<String,Histogram> histograms = new HashMap<String,Histogram>();

    public ResultSet() {

    }

    public ResultSet(SampleSet samples, TimeSurface surface){
        id = samples.pset.id + "_" + surface.id;

        PointSet targets = samples.pset;
        // Evaluate the surface at all points in the pointset
        int[] times = samples.eval(surface);
        buildHistograms(times, targets);

    }

    protected void buildHistograms(int[] times, PointSet targets) {
        for (Entry<String, int[]> cat : targets.properties.entrySet()) {
            String catId = cat.getKey();
            int[] mags = cat.getValue();
            this.histograms.put(catId, new Histogram(times, mags));
        }
    }

    /**
     * Sum the values of all categories at all time limits within the bounds of the search.
     */
    public long sum () {
        return sum(null);
    }
    
    /**
     * Sum the values of all categories up to the time limit specified (in seconds).
     */
    public long sum(Integer timeLimit) {

        long value = 0l;

        int maxMinutes;

        if(timeLimit != null)
            maxMinutes = timeLimit / 60;
        else
            maxMinutes = Integer.MAX_VALUE;

        for(String k : histograms.keySet()) {
            int minute = 0;
            for(int v : histograms.get(k).sums) {
                if(minute < maxMinutes)
                    value += v;
                minute++;
            }
        }

        return value;
    }


    /**
     * Each origin will yield CSV with columns category,min,q25,q50,q75,max
     * Another column for the origin ID would allow this to extend to many-to-many.
     */
    void toCsv() {

    }

    public void writeJson(OutputStream output) {
        writeJson(output, null);
    }

    public void writeJson(OutputStream output, PointSet ps) {
        try {
            JsonFactory jsonFactory = new JsonFactory(); 

            JsonGenerator jgen = jsonFactory.createGenerator(output);
            jgen.setCodec(new ObjectMapper());

            jgen.writeStartObject(); {	

                if(ps == null) {
                    jgen.writeObjectFieldStart("properties"); {
                        if (id != null)
                            jgen.writeStringField("id", id);
                    }
                    jgen.writeEndObject();
                }
                else {
                    ps.writeJsonProperties(jgen);
                }

                jgen.writeObjectFieldStart("data"); {
                    for(String propertyId : histograms.keySet()) {

                        jgen.writeObjectFieldStart(propertyId); {
                            histograms.get(propertyId).writeJson(jgen);
                        }
                        jgen.writeEndObject();

                    }
                }
                jgen.writeEndObject();
            }
            jgen.writeEndObject();

            jgen.close();
        } catch (IOException ioex) {
            LOG.info("IOException, connection may have been closed while streaming JSON.");
        }
    }
}
@@ -1443,35 +1443,41 @@
 m the values of 
-all
+specified
  categories at a
@@ -1501,16 +1501,23 @@
 thin the
+%0A     *
  bounds 
@@ -1530,16 +1530,69 @@
  search.
+ If no categories are specified, sum all categories. 
 %0A     */
@@ -1613,16 +1613,36 @@
 ng sum (
+String... categories
 ) %7B%0A    
@@ -1656,20 +1656,42 @@
 urn sum(
-null
+(Integer) null, categories
 );%0A    %7D
@@ -1729,19 +1729,29 @@
 lues of 
-all
+the specified
  categor
@@ -1784,16 +1784,23 @@
 pecified
+%0A     *
  (in sec
@@ -1809,57 +1809,243 @@
 ds).
-%0A     */%0A    public long sum(Integer timeLimit) %7B
+ If no categories are specified, sum all categories.%0A     */%0A    public long sum(Integer timeLimit, String... categories) %7B%0A        %0A        if (categories.length == 0)%0A            categories = (String%5B%5D) histograms.keySet().toArray();
 %0A%0A  
@@ -2245,35 +2245,26 @@
 ing k : 
-histograms.keySet()
+categories
 ) %7B%0A    

allow summing individual attributes. fix #1674.