class StatisticsControllerImpl implements StatisticsController, Controller<StatisticsModelImpl> {

    private final StatisticsBuilder[] statisticsBuilders;

    public StatisticsControllerImpl() {
        statisticsBuilders = Lookup.getDefault().lookupAll(StatisticsBuilder.class).toArray(new StatisticsBuilder[0]);
    }

    @Override
    public Class<StatisticsModelImpl> getModelClass() {
        return StatisticsModelImpl.class;
    }

    @Override
    public StatisticsModelImpl newModel(Workspace workspace) {
        return new StatisticsModelImpl(workspace);
    }

    @Override
    public StatisticsModelImpl getModel() {
        return Controller.super.getModel();
    }

    @Override
    public StatisticsModelImpl getModel(Workspace workspace) {
        return Controller.super.getModel(workspace);
    }

    @Override
    public void execute(final Statistics statistics, LongTaskListener listener) {<FILL_FUNCTION_BODY>}

    @Override
    public void execute(Statistics statistics) {
        StatisticsModelImpl model = getModel();
        if (statistics instanceof DynamicStatistics) {
            executeDynamic((DynamicStatistics) statistics, null, model);
        } else {
            executeStatic(statistics, model);
        }
    }

    private void executeStatic(Statistics statistics, StatisticsModelImpl model) {
        GraphController graphController = Lookup.getDefault().lookup(GraphController.class);
        GraphModel graphModel = graphController.getGraphModel(model.getWorkspace());
        statistics.execute(graphModel);
        model.addReport(statistics);
    }

    private void executeDynamic(DynamicStatistics statistics, DynamicLongTask dynamicLongTask,
                                StatisticsModelImpl model) {
        GraphController graphController = Lookup.getDefault().lookup(GraphController.class);
        GraphModel graphModel = graphController.getGraphModel();

        double window = statistics.getWindow();
        double tick = statistics.getTick();

        GraphView currentView = graphModel.getVisibleView();
        Interval bounds = statistics.getBounds();
        if (bounds == null) {
            if (currentView.isMainView()) {
                bounds = graphModel.getTimeBounds();
            } else {
                bounds = currentView.getTimeInterval();
            }
            statistics.setBounds(bounds);
        }

        if (dynamicLongTask != null) {
            //Count
            int c = (int) ((bounds.getHigh() - window - bounds.getLow()) / tick);
            dynamicLongTask.start(c);
        }

        //Init
        statistics.execute(graphModel);

        //Loop
        for (double low = bounds.getLow(); low <= bounds.getHigh() - window; low += tick) {
            double high = low + window;

            Graph graph = graphModel.getGraphVisible();

            graph.writeLock();
            try {
                GraphView view = graphModel.createView();
                Subgraph g = graphModel.getGraph(view);

                TimeIndex<Node> nodeIndex = graphModel.getNodeTimeIndex(currentView);
                if (Double.isInfinite(nodeIndex.getMinTimestamp()) && Double.isInfinite(nodeIndex.getMaxTimestamp())) {
                    for (Node node : graph.getNodes()) {
                        g.addNode(node);
                    }
                } else {
                    for (Node node : nodeIndex.get(new Interval(low, high))) {
                        g.addNode(node);
                    }
                }

                TimeIndex<Edge> edgeIndex = graphModel.getEdgeTimeIndex(currentView);
                if (Double.isInfinite(edgeIndex.getMinTimestamp()) && Double.isInfinite(edgeIndex.getMaxTimestamp())) {
                    for (Edge edge : graph.getEdges()) {
                        if (g.contains(edge.getSource()) && g.contains(edge.getTarget())) {
                            g.addEdge(edge);
                        }
                    }
                } else {
                    for (Edge edge : edgeIndex.get(new Interval(low, high))) {
                        if (g.contains(edge.getSource()) && g.contains(edge.getTarget())) {
                            g.addEdge(edge);
                        }
                    }
                }

                statistics.loop(g.getView(), new Interval(low, high));
            } finally {
                graph.writeUnlock();
                graph.readUnlockAll();
            }

            //Cancelled?
            if (dynamicLongTask != null && dynamicLongTask.isCancelled()) {
                return;
            } else if (dynamicLongTask != null) {
                dynamicLongTask.progress();
            }
        }
        statistics.end();
        model.addReport(statistics);
    }

    @Override
    public StatisticsBuilder getBuilder(Class<? extends Statistics> statisticsClass) {
        for (StatisticsBuilder b : statisticsBuilders) {
            if (b.getStatisticsClass().equals(statisticsClass)) {
                return b;
            }
        }
        return null;
    }

    private static class DynamicLongTask implements LongTask {

        private final LongTask longTask;
        private ProgressTicket progressTicket;
        private boolean cancel = false;

        public DynamicLongTask(DynamicStatistics statistics) {
            if (statistics instanceof LongTask) {
                this.longTask = (LongTask) statistics;
            } else {
                this.longTask = null;
            }
        }

        @Override
        public boolean cancel() {
            cancel = true;
            if (longTask != null) {
                this.longTask.cancel();
            }
            return true;
        }

        @Override
        public void setProgressTicket(ProgressTicket progressTicket) {
            this.progressTicket = progressTicket;
        }

        public void start(int iterations) {
            Progress.start(progressTicket, iterations);
        }

        public void progress() {
            Progress.progress(progressTicket);
        }

        public boolean isCancelled() {
            return cancel;
        }
    }
}

        StatisticsBuilder builder = getBuilder(statistics.getClass());
        LongTaskExecutor executor = new LongTaskExecutor(true, "Statistics " + builder.getName(), 10);
        if (listener != null) {
            executor.setLongTaskListener(listener);
        }

        final StatisticsModelImpl model = getModel();
        if (statistics instanceof DynamicStatistics) {
            final DynamicLongTask dynamicLongTask = new DynamicLongTask((DynamicStatistics) statistics);
            executor.execute(dynamicLongTask, new Runnable() {

                @Override
                public void run() {
                    executeDynamic((DynamicStatistics) statistics, dynamicLongTask, model);
                }
            }, builder.getName(), null);
        } else {
            LongTask task = statistics instanceof LongTask ? (LongTask) statistics : null;
            executor.execute(task, new Runnable() {

                @Override
                public void run() {
                    executeStatic(statistics, model);
                }
            }, builder.getName(), null);
        }
    
<no_super_class>