class ExporterCSV implements GraphExporter, CharacterExporter, LongTask {

    private static final String SEPARATOR = ";";
    private static final String EOL = "\n";
    /**
     * Formatter for limiting precision to 6 decimals, avoiding precision errors (epsilon).
     */
    private static final DecimalFormat FORMAT = new DecimalFormat("0.######");

    static {
        DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(Locale.ENGLISH);
        FORMAT.setDecimalFormatSymbols(symbols);
    }

    //Settings
    private boolean edgeWeight = true;
    private boolean writeZero = true;
    private boolean header = true;
    private boolean list = false;
    //Architecture
    private Workspace workspace;
    private Writer writer;
    private boolean exportVisible;
    private boolean cancel = false;
    private ProgressTicket progressTicket;

    @Override
    public boolean execute() {
        GraphModel graphModel = workspace.getLookup().lookup(GraphModel.class);
        Graph graph = exportVisible ? graphModel.getGraphVisible() : graphModel.getGraph();

        graph.readLock();
        try {
            exportData(graph);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            graph.readUnlock();
            Progress.finish(progressTicket);
        }

        return !cancel;
    }

    private void exportData(Graph graph) throws Exception {
        int max = graph.getNodeCount();

        Progress.start(progressTicket, max);

        if (!list) {
            if (header) {
                writer.append(SEPARATOR);
                int i = 0;
                NodeIterable itr = graph.getNodes();
                for (Node node : itr) {
                    writeMatrixNode(node, i++ < max - 1);
                    if (cancel) {
                        itr.doBreak();
                        return;
                    }
                }
                writer.append(EOL);
            }
        }

        if (list) {
            NodeIterable itr = graph.getNodes();
            for (Node n : itr) {
                List<Node> neighbours = new ArrayList<>();
                for (Edge e : graph.getEdges(n)) {
                    if (!e.isDirected() || (e.isDirected() && n == e.getSource())) {
                        Node m = graph.getOpposite(n, e);
                        neighbours.add(m);
                    }
                }

                writeListNode(n, !neighbours.isEmpty());
                for (int j = 0; j < neighbours.size(); j++) {
                    writeListNode(neighbours.get(j), j < neighbours.size() - 1);

                }
                writer.append(EOL);

                if (cancel) {
                    itr.doBreak();
                    return;
                }
            }
        } else {
            Node[] nodes = graph.getNodes().toArray();
            for (Node n : nodes) {
                if (cancel) {
                    return;
                }
                writeMatrixNode(n, true);
                for (int j = 0; j < nodes.length; j++) {
                    Node m = nodes[j];
                    EdgeIterable edges = graph.getEdges(n, m);
                    writeEdge(edges, j < nodes.length - 1);
                }
                Progress.progress(progressTicket);
                writer.append(EOL);
            }
        }

        Progress.finish(progressTicket);
    }

    private void writeEdge(EdgeIterable edges, boolean writeSeparator) throws IOException {
        float weight = 0;
        boolean anyEdge = false;
        for (Edge edge : edges) {
            anyEdge = true;
            weight += edge.getWeight();
        }

        if (anyEdge) {
            if (edgeWeight) {
                writer.append(FORMAT.format(weight));
            } else {
                writer.append(FORMAT.format(1.0));
            }
        } else {
            if (writeZero) {
                writer.append("0");
            }
        }

        if (writeSeparator) {
            writer.append(SEPARATOR);
        }
    }

    private void writeMatrixNode(Node node, boolean writeSeparator) throws IOException {<FILL_FUNCTION_BODY>}

    private void writeListNode(Node node, boolean writeSeparator) throws IOException {
        Object label = node.getId();
        writer.append(label.toString());
        if (writeSeparator) {
            writer.append(SEPARATOR);
        }
    }

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

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

    public boolean isEdgeWeight() {
        return edgeWeight;
    }

    public void setEdgeWeight(boolean edgeWeight) {
        this.edgeWeight = edgeWeight;
    }

    public boolean isHeader() {
        return header;
    }

    public void setHeader(boolean header) {
        this.header = header;
    }

    public boolean isWriteZero() {
        return writeZero;
    }

    public void setWriteZero(boolean writeZero) {
        this.writeZero = writeZero;
    }

    public boolean isList() {
        return list;
    }

    public void setList(boolean list) {
        this.list = list;
    }

    @Override
    public boolean isExportVisible() {
        return exportVisible;
    }

    @Override
    public void setExportVisible(boolean exportVisible) {
        this.exportVisible = exportVisible;
    }

    @Override
    public void setWriter(Writer writer) {
        this.writer = writer;
    }

    @Override
    public Workspace getWorkspace() {
        return workspace;
    }

    @Override
    public void setWorkspace(Workspace workspace) {
        this.workspace = workspace;
    }
}

        if (header) {
            Object label = node.getId();
            writer.append(label.toString());
            if (writeSeparator) {
                writer.append(SEPARATOR);
            }
        }
    
<no_super_class>