class StatisticsModelUIImpl implements StatisticsModelUI {

    private final Workspace workspace;
    private final List<StatisticsUI> invisibleList;
    private final Map<StatisticsUI, String> resultMap;
    private final List<Statistics> runningList;
    //Listeners
    private final List<ChangeListener> listeners;

    public StatisticsModelUIImpl(Workspace workspace) {
        this.workspace = workspace;
        runningList = Collections.synchronizedList(new ArrayList<Statistics>());
        invisibleList = new ArrayList<>();
        resultMap = new HashMap<>();
        listeners = new ArrayList<>();
    }

    public void addResult(StatisticsUI ui) {
        if (resultMap.containsKey(ui) && ui.getValue() == null) {
            resultMap.remove(ui);
        } else {
            resultMap.put(ui, ui.getValue());
        }
        fireChangeEvent();
    }

    @Override
    public String getResult(StatisticsUI statisticsUI) {
        return resultMap.get(statisticsUI);
    }

    @Override
    public String getReport(Class<? extends Statistics> statistics) {
        StatisticsController controller = Lookup.getDefault().lookup(StatisticsController.class);
        return controller.getModel(workspace).getReport(statistics);
    }

    @Override
    public boolean isStatisticsUIVisible(StatisticsUI statisticsUI) {
        return !invisibleList.contains(statisticsUI);
    }

    @Override
    public boolean isRunning(StatisticsUI statisticsUI) {
        for (Statistics s : runningList.toArray(new Statistics[0])) {
            if (statisticsUI.getStatisticsClass().equals(s.getClass())) {
                return true;
            }
        }
        return false;
    }

    public void setRunning(Statistics statistics, boolean running) {
        if (!running) {
            if (runningList.remove(statistics)) {
                fireChangeEvent();
            }
        } else if (!runningList.contains(statistics)) {
            runningList.add(statistics);
            fireChangeEvent();
        }
    }

    @Override
    public Statistics getRunning(StatisticsUI statisticsUI) {
        for (Statistics s : runningList.toArray(new Statistics[0])) {
            if (statisticsUI.getStatisticsClass().equals(s)) {
                return s;
            }
        }
        return null;
    }

    public void setVisible(StatisticsUI statisticsUI, boolean visible) {
        if (visible) {
            if (invisibleList.remove(statisticsUI)) {
                fireChangeEvent();
            }
        } else if (!invisibleList.contains(statisticsUI)) {
            invisibleList.add(statisticsUI);
            fireChangeEvent();
        }
    }

    @Override
    public void addChangeListener(ChangeListener changeListener) {
        if (!listeners.contains(changeListener)) {
            listeners.add(changeListener);
        }
    }

    @Override
    public void removeChangeListener(ChangeListener changeListener) {
        listeners.remove(changeListener);
    }

    public void fireChangeEvent() {
        ChangeEvent evt = new ChangeEvent(this);
        for (ChangeListener listener : listeners) {
            listener.stateChanged(evt);
        }
    }

    public Workspace getWorkspace() {
        return workspace;
    }

    //PERSISTENCE
    public void writeXML(XMLStreamWriter writer) throws XMLStreamException {

        writer.writeStartElement("results");
        for (Map.Entry<StatisticsUI, String> entry : resultMap.entrySet()) {
            if (entry.getValue() != null && !entry.getValue().isEmpty()) {
                writer.writeStartElement("result");
                writer.writeAttribute("class", entry.getKey().getClass().getName());
                writer.writeAttribute("value", entry.getValue());
                writer.writeEndElement();
            }
        }
        writer.writeEndElement();
    }

    public void readXML(XMLStreamReader reader) throws XMLStreamException {<FILL_FUNCTION_BODY>}
}

        Collection<? extends StatisticsUI> uis = Lookup.getDefault().lookupAll(StatisticsUI.class);

        boolean end = false;
        while (reader.hasNext() && !end) {
            int type = reader.next();

            switch (type) {
                case XMLStreamReader.START_ELEMENT:
                    String name = reader.getLocalName();
                    if ("result".equalsIgnoreCase(name)) {
                        String classStr = reader.getAttributeValue(null, "class");
                        StatisticsUI resultUI = null;
                        for (StatisticsUI ui : uis) {
                            if (ui.getClass().getName().equals(classStr)) {
                                resultUI = ui;
                            }
                        }
                        if (resultUI != null) {
                            String value = reader.getAttributeValue(null, "value");
                            resultMap.put(resultUI, value);
                        }
                    }
                    break;
                case XMLStreamReader.END_ELEMENT:
                    if ("statisticsmodelui".equalsIgnoreCase(reader.getLocalName())) {
                        end = true;
                    }
                    break;
            }
        }
    
<no_super_class>