package xyz.ignatz.flowchart.module;


import java.util.*;

public class Block {

    class Edge {
        Node src;
        String label;
        public Edge(Node src, String label) {
            this.src = src;
            this.label = label;
        }
    }

    Node start;
    Map<String, HashSet<Edge>> nullEdges = new HashMap<>();

    public Block(Node node) {
        start = node;
        node.tps.forEach((label, dst) -> {
            if (dst == null) {
                nullEdges.putIfAbsent(label, new HashSet<>());
                nullEdges.get(label).add(new Edge(node, label));
            }
        });
    }

    public Node getStart() {
        return start;
    }

    public void connectLoopJudgement(Block judgement, boolean judgeFirst) {
        judgement.connect(start, "true");
        connect(judgement, Arrays.asList("", "continue"));
        modifyTpType("false", "");
        modifyTpType("break", "");
        if (judgeFirst) start = judgement.start;
    }

    public void connect(Block next) {
        connect(next,"");
    }

    public void connect(Block next, String type) {
        connect(next, Arrays.asList(type));
    }

    public void connect(Block next, Collection<String> types) {
        if (next == null) return;
        types.forEach(type -> connect(next.start, type));
        merge(next);
    }

    public void modifyTpType(String old, String type) {
        Objects.requireNonNull(old);
        Objects.requireNonNull(type);
        if (type.equals(old) || !nullEdges.containsKey(old)) return;
        nullEdges.putIfAbsent(type, new HashSet<>());
        nullEdges.get(type).addAll(nullEdges.remove(old));
    }


    void connect(Node dst, String type) {
        Set<Edge> edges = nullEdges.remove(type);
        if (edges == null) return;
        edges.forEach(edge -> edge.src.connect(dst, edge.label));
    }

    void merge(Block other) {
        other.nullEdges.forEach((type, edges) ->
                nullEdges.merge(type, edges, (old, value) -> {
                    old.addAll(value);
                    return old;
                })
        );
        other.nullEdges = nullEdges;
    }
}
