/**
 * Copyright (c) 2019, RTE (http://www.rte-france.com)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package com.powsybl.cgmes.conversion;

import java.util.HashMap;
import java.util.Map;

import com.powsybl.cgmes.model.CgmesTerminal;
import com.powsybl.iidm.network.SwitchKind;
import com.powsybl.iidm.network.VoltageLevel;

/**
 * @author Luma Zamarreño <zamarrenolm at aia.es>
 */
public class NodeMapping {

    public NodeMapping() {
        cgmes2iidm = new HashMap<>(100);
        voltageLevelNumNodes = new HashMap<>(100);
    }

    public int iidmNodeForTerminal(CgmesTerminal t, VoltageLevel vl) {
        int iidmNodeForConductingEquipment = cgmes2iidm.computeIfAbsent(t.id(), id -> add(id, vl));
        // Add internal connection from terminal to connectivity node
        int iidmNodeForConnectivityNode = cgmes2iidm.computeIfAbsent(t.connectivityNode(), id -> add(id, vl));

        // For node-breaker models we create an internal connection between
        // the terminal and its connectivity node
        // Because there are some node-breaker models that,
        // in addition to the information of opened switches also set
        // the terminal.connected property to false,
        // we have decided to create fictitious switches to precisely
        // map this situation to IIDM

        if (t.connected()) {
            // TODO(Luma): do not add an internal connection if is has already been added?
            vl.getNodeBreakerView().newInternalConnection()
                    .setNode1(iidmNodeForConductingEquipment)
                    .setNode2(iidmNodeForConnectivityNode)
                    .add();
        } else {
            vl.getNodeBreakerView().newSwitch()
                    .setFictitious(true)
                    // Use the id and name of terminal
                    .setId(t.id())
                    .setName(t.name())
                    .setNode1(iidmNodeForConductingEquipment)
                    .setNode2(iidmNodeForConnectivityNode)
                    .setOpen(true)
                    .setKind(SwitchKind.BREAKER)
                    .add();
        }

        return iidmNodeForConductingEquipment;
    }

    public int iidmNodeForConnectivityNode(String id, VoltageLevel vl) {
        return cgmes2iidm.computeIfAbsent(id, k -> add(k, vl));
    }

    private int add(String id, VoltageLevel vl) {
        // The identifier id could be a connectivityNode id or a Terminal id
        int iidmNode = newNode(vl);
        cgmes2iidm.put(id, iidmNode);
        return iidmNode;
    }

    private int newNode(VoltageLevel vl) {
        // Reserve a node number in this voltage level
        // If the voltage level does not exist in the mapping, iidmNode will be zero,
        // If a previous value was stored, new value is computed with "sum" 1
        // We want a zero-based index, so -1 + ...
        int numNodes = voltageLevelNumNodes.merge(vl, 1, Integer::sum);
        if (vl.getNodeBreakerView().getNodeCount() < numNodes) {
            // +10 to avoid calling setNodeCount too many times
            vl.getNodeBreakerView().setNodeCount(numNodes + 10);
        }
        return numNodes - 1;
    }

    private final Map<String, Integer> cgmes2iidm;
    private final Map<VoltageLevel, Integer> voltageLevelNumNodes;
}

@@ -302,57 +302,8 @@
 n;%0A%0A
-import java.util.HashMap;%0Aimport java.util.Map;%0A%0A
 impo
@@ -435,16 +435,65 @@
 Level;%0A%0A
+import java.util.HashMap;%0Aimport java.util.Map;%0A%0A
 /**%0A * @
@@ -849,32 +849,32 @@
 id(), id -%3E 
-add(id, 
+newNode(
 vl));%0A      
@@ -1038,16 +1038,16 @@
  -%3E 
-add(id, 
+newNode(
 vl))
@@ -2457,252 +2457,20 @@
  -%3E 
-add(k, vl));%0A    %7D%0A%0A    private int add(String id, VoltageLevel vl) %7B%0A        // The identifier id could be a connectivityNode id or a Terminal id%0A        int iidmNode = newNode(vl);%0A        cgmes2iidm.put(id, iidmNode);%0A        return iidmNode
+newNode(vl))
 ;%0A  

Fix ConcurrentModificationException in Java >= 9