class DynamicClusteringCoefficient implements DynamicStatistics, LongTask {

    public static final String DYNAMIC_AVG_CLUSTERING_COEFFICIENT = "dynamic_avg_clustering";
    public static final String DYNAMIC_CLUSTERING_COEFFICIENT = "dynamic_clustering";
    //Data
    private GraphModel graphModel;
    private double window;
    private double tick;
    private Interval bounds;
    private boolean isDirected;
    private boolean averageOnly;
    private boolean cancel = false;
    private ClusteringCoefficient clusteringCoefficientStat;
    //Cols
    private Column dynamicCoefficientColumn;
    //Average
    private Column dynamicAverageCoefficientColumn;
    private Map<Double, Double> averages;

    public DynamicClusteringCoefficient() {
        GraphController graphController = Lookup.getDefault().lookup(GraphController.class);
        if (graphController != null && graphController.getGraphModel() != null) {
            isDirected = graphController.getGraphModel().isDirected();
        }
    }

    @Override
    public void execute(GraphModel graphModel) {<FILL_FUNCTION_BODY>}

    @Override
    public String getReport() {
        //Time series
        XYSeries dSeries = ChartUtils.createXYSeries(averages, "Clustering Coefficient Time Series");

        XYSeriesCollection dataset = new XYSeriesCollection();
        dataset.addSeries(dSeries);

        JFreeChart chart = ChartFactory.createXYLineChart(
            "Clustering Coefficient",
            "Time",
            "Average Clustering Coefficient",
            dataset,
            PlotOrientation.VERTICAL,
            true,
            false,
            false);

        chart.removeLegend();
        ChartUtils.decorateChart(chart);
        ChartUtils.scaleChart(chart, dSeries, false);
        String coefficientImageFile = ChartUtils.renderChart(chart, "coefficient-ts.png");

        NumberFormat f = new DecimalFormat("#0.000000");

        String report = "<HTML> <BODY> <h1>Dynamic Clustering Coefficient Report </h1> "
            + "<hr>"
            + "<br> Bounds: from " + f.format(bounds.getLow()) + " to " + f.format(bounds.getHigh())
            + "<br> Window: " + window
            + "<br> Tick: " + tick
            + "<br><br><h2> Average clustering cloefficient over time: </h2>"
            + "<br /><br />" + coefficientImageFile;

        /*for (Interval<Double> average : averages) {
        report += average.toString(dynamicModel.getTimeFormat().equals(DynamicModel.TimeFormat.DOUBLE)) + "<br />";
        }*/
        report += "<br /><br /></BODY></HTML>";
        return report;
    }

    @Override
    public void loop(GraphView window, Interval interval) {
        Graph graph;
        if (isDirected) {
            graph = graphModel.getDirectedGraph(window);
        } else {
            graph = graphModel.getUndirectedGraph(window);
        }
        TimeRepresentation tr = graphModel.getConfiguration().getTimeRepresentation();

        graph.readLock();

        try {
            clusteringCoefficientStat = new ClusteringCoefficient();
            clusteringCoefficientStat.setDirected(isDirected);
            clusteringCoefficientStat.triangles(graph);

            //Columns
            if (!averageOnly) {
                double[] coefficients = clusteringCoefficientStat.getCoefficientReuslts();
                int i = 0;
                for (Node n : graph.getNodes()) {
                    double coef = coefficients[i++];

                    switch (tr) {
                        case INTERVAL:
                            n.setAttribute(dynamicCoefficientColumn, coef,
                                new Interval(interval.getLow(), interval.getLow() + tick));
                            break;
                        case TIMESTAMP:
                            n.setAttribute(dynamicCoefficientColumn, coef, interval.getLow());
                            n.setAttribute(dynamicCoefficientColumn, coef, interval.getHigh());
                            break;
                    }

                    if (cancel) {
                        break;
                    }
                }
            }
        } finally {
            graph.readUnlockAll();
        }

        //Average
        double avg = clusteringCoefficientStat.getAverageClusteringCoefficient();
        graphModel.getGraphVisible().setAttribute(DYNAMIC_AVG_CLUSTERING_COEFFICIENT, avg, interval.getLow());
        graphModel.getGraphVisible().setAttribute(DYNAMIC_AVG_CLUSTERING_COEFFICIENT, avg, interval.getHigh());

        averages.put(interval.getLow(), avg);
        averages.put(interval.getHigh(), avg);
    }

    @Override
    public void end() {
        clusteringCoefficientStat = null;
    }

    @Override
    public double getWindow() {
        return window;
    }

    @Override
    public void setWindow(double window) {
        this.window = window;
    }

    @Override
    public double getTick() {
        return tick;
    }

    @Override
    public void setTick(double tick) {
        this.tick = tick;
    }

    @Override
    public Interval getBounds() {
        return bounds;
    }

    @Override
    public void setBounds(Interval bounds) {
        this.bounds = bounds;
    }

    public boolean isDirected() {
        return isDirected;
    }

    public void setDirected(boolean isDirected) {
        this.isDirected = isDirected;
    }

    public boolean isAverageOnly() {
        return averageOnly;
    }

    public void setAverageOnly(boolean averageOnly) {
        this.averageOnly = averageOnly;
    }

    @Override
    public boolean cancel() {
        cancel = true;
        return true;
    }

    @Override
    public void setProgressTicket(ProgressTicket progressTicket) {
    }
}

        this.graphModel = graphModel;
        this.isDirected = graphModel.isDirected();
        this.averages = new HashMap<>();

        //Attributes cols
        if (!averageOnly) {
            TimeRepresentation tr = graphModel.getConfiguration().getTimeRepresentation();

            Table nodeTable = graphModel.getNodeTable();
            Class columnType =
                tr.equals(TimeRepresentation.INTERVAL) ? IntervalDoubleMap.class : TimestampDoubleMap.class;
            ColumnUtils.cleanUpColumns(nodeTable, new String[] {DYNAMIC_CLUSTERING_COEFFICIENT}, columnType);

            dynamicCoefficientColumn = nodeTable.getColumn(DYNAMIC_CLUSTERING_COEFFICIENT);
            if (dynamicCoefficientColumn == null) {
                dynamicCoefficientColumn = nodeTable.addColumn(DYNAMIC_CLUSTERING_COEFFICIENT, NbBundle
                        .getMessage(DynamicClusteringCoefficient.class,
                            "DynamicClusteringCoefficient.nodecolumn.ClusteringCoefficient"),
                    columnType, null);
            }
        }
    
<no_super_class>