<commit_before>package org.squiddev.cctweaks.core.network.controller;

import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.util.BlockPos;
import org.squiddev.cctweaks.api.UnorderedPair;
import org.squiddev.cctweaks.api.network.INetworkController;
import org.squiddev.cctweaks.api.network.INetworkNode;
import org.squiddev.cctweaks.api.network.IWorldNetworkNode;
import org.squiddev.cctweaks.api.network.Packet;
import org.squiddev.cctweaks.core.collections.MapChanges;
import org.squiddev.cctweaks.core.collections.MapsX;

import java.util.*;

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Sets.newHashSet;
import static com.google.common.collect.Sets.newHashSetWithExpectedSize;
import static java.util.Collections.*;

public final class NetworkController implements INetworkController {
	private Map<String, IPeripheral> peripherals = newHashMap();

	protected final Map<INetworkNode, Point> points;
	private Set<INetworkNode> nodeView;
	private Set<UnorderedPair<INetworkNode>> connectionCache;

	/**
	 * Construct a new network with a single node
	 *
	 * The node should not currently be attached to a network.
	 *
	 * @param node The node to construct it from.
	 */
	public NetworkController(INetworkNode node) {
		if (node.getAttachedNetwork() != null) {
			throw new IllegalArgumentException(String.format("%s is already attached to %s", node, node.getAttachedNetwork()));
		}

		points = newHashMap();

		Point point = new Point(node);
		points.put(node, point);
		point.attachToNetwork(this);
		peripheralsUpdate(point.refreshPeripherals(), null);

		ControllerValidator.validate(this);
	}

	/**
	 * Construct a new network from an existing set of nodes and points.
	 *
	 * These points will probably be already attached to a network.
	 *
	 * @param points         The node to point lookup map
	 * @param oldPeripherals The peripherals on the original network
	 */
	private NetworkController(Map<INetworkNode, Point> points, Map<String, IPeripheral> oldPeripherals) {
		Preconditions.checkNotNull(points, "Network points cannot be null");
		Preconditions.checkNotNull(oldPeripherals, "Old peripheral list cannot be null");

		this.points = points;

		// Add all points.
		Map<String, IPeripheral> peripherals = this.peripherals;
		for (Point point : points.values()) {
			INetworkNode node = point.node;
			if (node.getAttachedNetwork() != null) point.detachFromNetwork();

			point.attachToNetwork(this);
			peripherals.putAll(point.peripherals);
		}

		// Update peripherals
		peripheralsInvalidated(MapsX.changes(oldPeripherals, peripherals), null);

		ControllerValidator.validate(this);
	}

	//region Controller internals

	/**
	 * Get the point for the node or explode if it doesn't exist
	 *
	 * @param node The node to lookup
	 * @return The point
	 * @throws NullPointerException If the point cannot be found.
	 */
	private Point getPoint(INetworkNode node) {
		Preconditions.checkNotNull(node, "Node cannot be null");
		return Preconditions.checkNotNull(points.get(node), "Cannot find point for node %s", node);
	}

	/**
	 * Handle breaking a network.
	 *
	 * @param networks The networks to split into.
	 */
	private void handleSplit(Collection<Map<INetworkNode, Point>> networks) {
		// If there are no changes, then we just ignore it.
		if (networks.size() <= 1) return;

		Map<String, IPeripheral> peripheralMap = unmodifiableMap(peripherals);

		// Clear the structure. Make it impossible to add peripherals
		connectionCache = null;
		points.clear();
		peripherals = newHashMap();

		/*
			It is just easier to split the network, rather than keep one and split the others.
			If we ever keep one network, we should ideally keep the largest one.
		*/
		for (Map<INetworkNode, Point> network : networks) {
			new NetworkController(network, peripheralMap);
		}
	}
	//endregion

	//region Peripheral handling

	/**
	 * Update the controller's peripherals
	 *
	 * This will update the controller's peripheral map and notify the network.
	 *
	 * @param removed All peripherals which were removed
	 * @param added   All peripherals which were added
	 * @param exclude Set of points to exclude
	 */
	private void peripheralsUpdate(Map<String, IPeripheral> removed, Map<String, IPeripheral> added, Set<Point> exclude) {
		for (String entry : removed.keySet()) {
			peripherals.remove(entry);
		}
		peripherals.putAll(added);<commit_msg>Always clear the connection cache<commit_after>package org.squiddev.cctweaks.core.network.controller;

import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import dan200.computercraft.api.peripheral.IPeripheral;
import net.minecraft.util.BlockPos;
import org.squiddev.cctweaks.api.UnorderedPair;
import org.squiddev.cctweaks.api.network.INetworkController;
import org.squiddev.cctweaks.api.network.INetworkNode;
import org.squiddev.cctweaks.api.network.IWorldNetworkNode;
import org.squiddev.cctweaks.api.network.Packet;
import org.squiddev.cctweaks.core.collections.MapChanges;
import org.squiddev.cctweaks.core.collections.MapsX;

import java.util.*;

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Sets.newHashSet;
import static com.google.common.collect.Sets.newHashSetWithExpectedSize;
import static java.util.Collections.*;

public final class NetworkController implements INetworkController {
	private Map<String, IPeripheral> peripherals = newHashMap();

	protected final Map<INetworkNode, Point> points;
	private Set<INetworkNode> nodeView;
	private Set<UnorderedPair<INetworkNode>> connectionCache;

	/**
	 * Construct a new network with a single node
	 *
	 * The node should not currently be attached to a network.
	 *
	 * @param node The node to construct it from.
	 */
	public NetworkController(INetworkNode node) {
		if (node.getAttachedNetwork() != null) {
			throw new IllegalArgumentException(String.format("%s is already attached to %s", node, node.getAttachedNetwork()));
		}

		points = newHashMap();

		Point point = new Point(node);
		points.put(node, point);
		point.attachToNetwork(this);
		peripheralsUpdate(point.refreshPeripherals(), null);

		ControllerValidator.validate(this);
	}

	/**
	 * Construct a new network from an existing set of nodes and points.
	 *
	 * These points will probably be already attached to a network.
	 *
	 * @param points         The node to point lookup map
	 * @param oldPeripherals The peripherals on the original network
	 */
	private NetworkController(Map<INetworkNode, Point> points, Map<String, IPeripheral> oldPeripherals) {
		Preconditions.checkNotNull(points, "Network points cannot be null");
		Preconditions.checkNotNull(oldPeripherals, "Old peripheral list cannot be null");

		this.points = points;

		// Add all points.
		Map<String, IPeripheral> peripherals = this.peripherals;
		for (Point point : points.values()) {
			INetworkNode node = point.node;
			if (node.getAttachedNetwork() != null) point.detachFromNetwork();

			point.attachToNetwork(this);
			peripherals.putAll(point.peripherals);
		}

		// Update peripherals
		peripheralsInvalidated(MapsX.changes(oldPeripherals, peripherals), null);

		ControllerValidator.validate(this);
	}

	//region Controller internals

	/**
	 * Get the point for the node or explode if it doesn't exist
	 *
	 * @param node The node to lookup
	 * @return The point
	 * @throws NullPointerException If the point cannot be found.
	 */
	private Point getPoint(INetworkNode node) {
		Preconditions.checkNotNull(node, "Node cannot be null");
		return Preconditions.checkNotNull(points.get(node), "Cannot find point for node %s", node);
	}

	/**
	 * Handle breaking a network.
	 *
	 * @param networks The networks to split into.
	 */
	private void handleSplit(Collection<Map<INetworkNode, Point>> networks) {
		connectionCache = null;

		// If there are no changes, then we just ignore it.
		if (networks.size() <= 1) return;

		Map<String, IPeripheral> peripheralMap = unmodifiableMap(peripherals);

		// Clear the structure. Make it impossible to add peripherals
		points.clear();
		peripherals = newHashMap();

		/*
			It is just easier to split the network, rather than keep one and split the others.
			If we ever keep one network, we should ideally keep the largest one.
		*/
		for (Map<INetworkNode, Point> network : networks) {
			new NetworkController(network, peripheralMap);
		}
	}
	//endregion

	//region Peripheral handling

	/**
	 * Update the controller's peripherals
	 *
	 * This will update the controller's peripheral map and notify the network.
	 *
	 * @param removed All peripherals which were removed
	 * @param added   All peripherals which were added
	 * @param exclude Set of points to exclude
	 */
	private void peripheralsUpdate(Map<String, IPeripheral> removed, Map<String, IPeripheral> added, Set<Point> exclude) {
		for (String entry : removed.keySet()) {
			peripherals.remove(entry);
		}
		peripherals.putAll(added);
{'fraction_non_alphanumeric': 0.09841789416257501, 'fraction_numerical': 0.000872885979268958, 'mean_word_length': 4.535024154589372, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7491256', 'n_tokens_mistral': 2901, 'n_tokens_neox': 2648, 'n_words': 801}