GraphModel.java

package org.thewonderlemming.c4plantuml.graphml.model;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import org.thewonderlemming.c4plantuml.graphml.Build;
import org.thewonderlemming.c4plantuml.graphml.model.builder.WithDirection;
import org.thewonderlemming.c4plantuml.graphml.model.builder.WithId;

/**
 * The <graph> part of the representation of a GraphML stream.
 * <p>
 * It is based on JAXB.
 *
 * @author thewonderlemming
 *
 */
@XmlRootElement(name = GraphModel.TAG_NAME)
@XmlAccessorType(XmlAccessType.FIELD)
public class GraphModel {

    /**
     * The current model XML tag name.
     */
    public static final String TAG_NAME = "graph";

    @XmlAttribute(name = "edgedefault", required = true)
    private String edgeDefault;

    @XmlAttribute(name = "id", required = true)
    private String id;

    @XmlElement(name = DataModel.TAG_NAME)
    private MappedListDecorator<DataModel, String> seq1Data;

    @XmlElement(name = NodeModel.TAG_NAME)
    private MappedListDecorator<NodeModel, String> seq2Nodes;

    @XmlElement(name = EdgeModel.TAG_NAME)
    private MappedListDecorator<EdgeModel, String> seq3Edges;


    /**
     * A builder to the current {@link GraphModel} class.
     *
     * @return a new {@link GraphModel} instance.
     */
    public static WithId<String, WithDirection<WithData<WithNodes<WithEdges<Build<GraphModel>>>>>> builder() {

        return id -> edgeDefault -> data -> nodes -> edges -> () -> {

            final GraphModel graph = new GraphModel();
            graph.setId(id);
            graph.setEdgeDefault(edgeDefault);
            graph.setData(data);
            graph.setNodes(nodes);
            graph.setEdges(edges);

            return graph;
        };
    }

    /**
     * Default constructor.
     */
    private GraphModel() {
        // Does nothing but hiding the current constructor.
    }

    /**
     * Adds the given {@link DataModel} to the list if its {@link DataModel#getKey()} is not already there or replaces
     * it else.
     *
     * @param data the given {@link DataModel} to add/replace.
     */
    public void addOrReplaceData(final DataModel data) {
        this.seq1Data.addOrReplaceData(data);
    }

    /**
     * Adds the given {@link EdgeModel} to the list if its {@link EdgeModel#getId()} is not already there or replaces
     * it else.
     *
     * @param edge the given {@link EdgeModel} to add/replace.
     */
    public void addOrReplaceEdge(final EdgeModel edge) {
        this.seq3Edges.addOrReplaceData(edge);
    }

    /**
     * Adds the given {@link NodeModel} to the list if its {@link NodeModel#getId()} is not already there or replaces
     * it else.
     *
     * @param node the given {@link NodeModel} to add/replace.
     */
    public void addOrReplaceNode(final NodeModel node) {
        this.seq2Nodes.addOrReplaceData(node);
    }

    /**
     * Returns the current graph's properties list.
     *
     * @return the {@link DataModel} list.
     */
    public List<DataModel> getData() {
        return seq1Data;
    }

    /**
     * Returns the graph's &lt;edgedefault&gt; property.
     *
     * @return the &lt;edgedefault&gt; property.
     */
    public String getEdgeDefault() {
        return edgeDefault;
    }

    /**
     * Returns the graph's edges as a list.
     *
     * @return the graph {@link EdgeModel} list.
     */
    public List<EdgeModel> getEdges() {
        return seq3Edges;
    }

    /**
     * Returns the graph ID.
     *
     * @return the graph ID.
     */
    public String getId() {
        return id;
    }

    /**
     * Returns the graph(s nodes as a list.
     *
     * @return the graph {@link NodeModel} list.
     */
    public List<NodeModel> getNodes() {
        return seq2Nodes;
    }

    /**
     * Tells whether or not the current graph is a child of a node (or if it stands alone).
     *
     * @param node the {@link NodeModel} that is supposed to be the the parent node.
     * @return {@code true} if the graph is a child of the given {@code node}, {@code false} else.
     */
    public boolean isChildOfNode(final NodeModel node) {
        return this.id.equals(node.getId() + "::");
    }

    /**
     * Tells whether or not the current graph is empty.
     *
     * @return {@code true} if the graph is empty, {@code false} else.
     */
    public boolean isEmpty() {
        return this.seq1Data.isEmpty() && this.seq2Nodes.isEmpty() && this.seq3Edges.isEmpty();
    }

    /**
     * Tells whether or not the current graph is not empty.
     *
     * @return {@code true} if the graph is not empty, {@code false} else.
     */
    public boolean isNotEmpty() {
        return !this.isEmpty();
    }

    /**
     * Sets the graph's aspect.
     *
     * @param aspect the graph {@code aspect}.
     */
    public void setAspect(final String aspect) {

        this
            .addOrReplaceData(DataModel
                .builder()
                    .withKey(C4Keys.ASPECT)
                    .withValue(aspect)
                    .build());
    }

    /**
     * Sets the graph's ID.
     *
     * @param id the graph {@code id}
     */
    public void setId(final String id) {
        this.id = id;
    }

    /**
     * Sets a &lt;data&gt; tag of type {@link C4Keys#TITLE} and with the given value.
     *
     * @param title the data value to set.
     */
    public void setTitle(final String title) {

        this
            .addOrReplaceData(DataModel
                .builder()
                    .withKey(C4Keys.TITLE)
                    .withValue(title)
                    .build());
    }

    private void setData(final List<DataModel> data) {
        this.seq1Data = new MappedListDecorator<>(DataModel.class, data, DataModel::getKey);
    }

    private void setEdgeDefault(final String edgeDefault) {
        this.edgeDefault = edgeDefault;
    }

    private void setEdges(final List<EdgeModel> edges) {
        this.seq3Edges = new MappedListDecorator<>(EdgeModel.class, edges, EdgeModel::getId);
    }

    private void setNodes(final List<NodeModel> nodes) {
        this.seq2Nodes = new MappedListDecorator<>(NodeModel.class, nodes, NodeModel::getId);
    }
}