package game;
import game.gameplay.City;
import networks.BackboneProviderNetwork;
import networks.InternetProviderNetwork;
import networks.Network;
import networks.Network.NetworkType;
import networks.NetworkFactory;
import networks.devices.Device;
import java.util.*;
public class Internet {
/**
* Contains all ISPs. Note: ISPs can only be public.
*/
private final Map<String, InternetProviderNetwork> internetProviderNetworksMap;
/**
* Contains all Backbone networks. Note: Backbone networks can only be
* public.
*/
private final Map<String, BackboneProviderNetwork> backboneProviderNetworksMap;
/**
* Contains all networks with an IP.
*/
private final Map<String, Network> networkMap;
/**
* Contains all IPs and their registered addresses, if they have one.
*/
private final Map<String, String> addressMap;
/**
* Used when generating IPs to find an unused, random ip.
*/
public static List<Short> ipNumbers = new ArrayList<Short>(255);
public static final int BACKBONE_MULTIPLIER = 1;
public static final int ISP_MULTIPLIER = 2;
public static final int NETWORK_MULTIPLIER = 3;
public final int INITIAL_BACKBONE_SIZE;
public final int INITIAL_ISP_SIZE;
/**
* This is only created at the start of the game.
*
* @param cities list of cities in the world.
*/
public Internet(HashMap<String, City> cities) {
INITIAL_BACKBONE_SIZE = BACKBONE_MULTIPLIER * cities.size();
INITIAL_ISP_SIZE = (int) (INITIAL_BACKBONE_SIZE * (Math.random() * ISP_MULTIPLIER + 1));
int network_size = (int) (INITIAL_ISP_SIZE * (Math.random() * NETWORK_MULTIPLIER + 2)); // not very accurate, but it helps
backboneProviderNetworksMap = new HashMap<String, BackboneProviderNetwork>(INITIAL_BACKBONE_SIZE);
internetProviderNetworksMap = new HashMap<String, InternetProviderNetwork>(INITIAL_ISP_SIZE);
networkMap = new HashMap<String, Network>(network_size + INITIAL_ISP_SIZE + INITIAL_BACKBONE_SIZE);
addressMap = new HashMap<String, String>(network_size + INITIAL_ISP_SIZE + INITIAL_BACKBONE_SIZE);
for (short i = 1; i <= 256; i++) {
ipNumbers.add(i);
}
generateBackbones(cities);
generateIsps(INITIAL_ISP_SIZE, cities);
}
private void generateBackbones(HashMap<String, City> cities) {
// each ipRegion gets at least one backbone, possibly several
for (City city : cities.values()) {
BackboneProviderNetwork backbone = NetworkFactory.createBackbone(this, city);
short[] ip = {0, 1, 1, 1};
do {
ip[0] = generateIpByte(backbone.getIpRegion());
} while (networkMap.containsKey(ipToString(ip)) && networkMap.size() < 256);
backbone.setIp(ipToString(ip));
backboneProviderNetworksMap.put(backbone.getIp(), backbone);
networkMap.put(backbone.getIp(), backbone);
city.addNetwork(backbone);
}
}
private void generateIsps(int amount, HashMap<String, City> cities) {
List<City> citiesShuffled = new ArrayList<City>(cities.values());
for (int i = 0; i < amount; i++) {
float random = (float) (Math.random() * 2 - 1);
Collections.shuffle(citiesShuffled);
for (City c : citiesShuffled) {
if (c.getDensity() >= random) {
List<BackboneProviderNetwork> cityBackbones = new ArrayList<BackboneProviderNetwork>();
int isps = 0;
for (Network n : c.getNetworks().values()) {
if (n instanceof BackboneProviderNetwork) {
cityBackbones.add((BackboneProviderNetwork) n);
} else if (n instanceof InternetProviderNetwork) {
isps++;
}
}
if (cityBackbones.isEmpty() || isps > 5) {
continue;
}
BackboneProviderNetwork b = cityBackbones.get((int) (Math.random() * cityBackbones.size()));
if (b.getIpChildNetworkHashMap().size() < 256) {
InternetProviderNetwork isp = NetworkFactory.createISP(this, c);
b.registerNewIsp(isp, 1);
internetProviderNetworksMap.put(isp.getIp(), isp);
networkMap.put(isp.getIp(), isp);
c.addNetwork(isp);
break;
}
}
}
}
// check for cities without isps
for (City c : cities.values()) {
BackboneProviderNetwork b = null;
boolean hasIsp = false;
for (Network n : c.getNetworks().values()) {
if (n instanceof BackboneProviderNetwork) {
b = (BackboneProviderNetwork) n;
} else if (n instanceof InternetProviderNetwork) {
hasIsp = true;
break;
}
}
if (b == null || hasIsp) {
continue;
}
if (b.getIpChildNetworkHashMap().size() < 256) {
InternetProviderNetwork isp = NetworkFactory.createISP(this, c);
b.registerNewIsp(isp, 1);
internetProviderNetworksMap.put(isp.getIp(), isp);
networkMap.put(isp.getIp(), isp);
c.addNetwork(isp);
}
}
}
/**
* Adds a network to the internet(network map) and the specified ISP. Not for provider networks.
*/
public void addNetworkToInternet(Network network, InternetProviderNetwork isp) {
isp.registerNewNetwork(network, 1);
networkMap.put(network.getIp(), network);
network.setInternet(this);
}
/**
* Returns a list of networks of the given type.
*/
public Map<String, Network> getNetworksByType(NetworkType type) {
Map<String, Network> map = new HashMap<String, Network>();
for (Network n : networkMap.values()) {
if (n.getType() == type) {
map.put(n.getIp(), n);
}
}
return map;
}
/**
* Used to create a (somewhat) realistic, random ip loosely based on the
* ipv4 internet map. This is used mostly with the assign ip method, but can
* be useful for other things.
*/
public static short generateIpByte(Network.IpRegion ipRegion) {
return (short) (Math.random() * (ipRegion.max - ipRegion.min) + ipRegion.min);
}
/**
* Returns an ip to an object that calls this, also checks it and adds it
* to the dns map.
*/
public String assignIp(Network network) {
short[] ip = null;
short[] parentIp = ipFromString(network.getParent().getIp());
Collections.shuffle(ipNumbers);
for (short i = 0; i < 255; i++) {
// just randomly generate numbers for the isp, there are not enough to slow it down
switch (network.getType()) {
case ISP:
ip = new short[]{parentIp[0], ipNumbers.get(i), generateIpByte(Network.IpRegion.none), 1};
// networks always end in 1
break;
default:
ip = new short[]{parentIp[0], parentIp[1], ipNumbers.get(i), 1};
break;
}
if (!addressMap.containsValue(ip) && !networkMap.containsKey(ipToString(ip))) {
break;
}
}
return ipToString(ip);
}
/**
* Registers a url to an ip so that not everything is an IP, a player can buy an address.
*
* @return True if it was registered correctly, otherwise false.
*/
public boolean addAddress(String ip, String address) {
if (address.matches("^[\\d|\\w]{1,64}\\.\\w{2,3}$") && !addressMap.containsValue(address)) { // address regex
addressMap.put(address, ip);
return true; // "you have successfully registered the url " + url +
// " for the ip " + ip;
}
return false; // "Sorry, either that URL is already registered)."
}
/**
* Remove an address from the addressMap.
*
* @return True if the address map does not contain the address, otherwise false. This will return true even if it never contained the address.
*/
public boolean removeAddress(String address) {
addressMap.remove(address);
return !addressMap.containsKey(address);
}
/**
* Searches for the device with the given ip on the public internet.
*/
public Device getDevice(String ip) {
short[] a = ipFromString(ip); // used to search through the hashmap because it only lists networks, which always end in 1s
a[3] = 1;
System.out.println(networkMap.containsKey(ipToString(a)));
return networkMap.get(ipToString(a)).getDevice(ip);
}
/**
* Public dns ip request, gets the ip of a server at that address.
*/
public String getIp(String address) {
return addressMap.get(address);
}
/**
* Removes references to a network from all public DNSs(there may not be
* any) and the network map. You can either leave it up to the GC to
* remove, or use the network privately.
*/
public void removePublicNetwork(Network network) {
networkMap.remove(network.getIp());
// TODO remove graphical data, or put that in a better spot to be more modular
}
public static String ipToString(short[] ip) {
return ip[0] + "." + ip[1] + "." + ip[2] + "." + ip[3];
}
public static short[] ipFromString(String ip) {
short[] array = new short[4];
if (ip.matches("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")) {
Scanner scanner = new Scanner(ip);
scanner.useDelimiter("\\.");
for (int i = 0; i < 4; i++) {
array[i] = scanner.nextShort();
}
scanner.close();
}
return array;
}
public Map<String, InternetProviderNetwork> getInternetProviderNetworksMap() {
return Collections.unmodifiableMap(internetProviderNetworksMap);
}
public Map<String, BackboneProviderNetwork> getBackboneProviderNetworksMap() {
return Collections.unmodifiableMap(backboneProviderNetworksMap);
}
public Map<String, Network> getNetworkMap() {
return Collections.unmodifiableMap(networkMap);
}
public Map<String, String> getAddressMap() {
return Collections.unmodifiableMap(addressMap);
}
public static List<Short> getIpNumbers() {
return Collections.unmodifiableList(ipNumbers);
}
}