package networks.devices;
import com.badlogic.gdx.math.Vector2;
import connection.Connectable;
import connection.Connection;
import connection.Port;
import gui.HakdSprite;
import gui.windows.device.DeviceScene;
import networks.Network;
import networks.devices.parts.*;
import networks.devices.parts.Part.Brand;
import networks.devices.parts.Part.Model;
import networks.devices.parts.Part.PartType;
import other.File;
import other.Util;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public /*abstract*/ class Device implements Connectable {
Network network;
int level;
String ip = ""; // all network variables will be in IP format
final Map<String, Connection> connections = new HashMap<String, Connection>();
final Map<Integer, Port> ports = new HashMap<Integer, Port>(); // portNumber, program / if its closed just delete it
File logs; // TODO make this a file instead connecting from and the action after that
Brand brand; // for example bell, or HQ
Model model;
int memoryCapacity; // in MB, additive
int storageCapacity; // in ???, additive
int cpuSpeed; // in MHz, additive
int gpuSpeed; // in MHz, additive
// objects
final Set<Part> parts = new HashSet<Part>();
int partLimit;
DeviceType type;
// gui
Vector2 isoPos;
DeviceScene deviceScene;
HakdSprite tile;
// default files
private final File root = new File("root", null); // root directory of the storage filesystem, rm -rf /
private File sys = new File("sys", null); // operating system files, !FUN!
private File home = new File("home", null); // random files people save
private File bin = new File("bin", null); // (python)programs able to run
private File log = new File("log", null); // these log arrays have infinite storage, thanks to a new leap in quantum physics
public Device() { // TODO: have random smartphone connections and disconnections. smartphones are like insects on a network, many types, random behavior, and there are lots of them
root.setDevice(this);
root.addFile(sys);
root.addFile(home);
root.addFile(bin);
root.addFile(log);
try {
for (int i = 0; i < 3; i++) {
home.addFile(Util.getFileData("bash", (int) (Math.random() * 9) + ""));
}
for (String f : Util.PROGRAMS.keySet()) {
bin.addFile(new File(f, Util.PROGRAMS.get(f)));
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public final boolean connect(Device client, Port clientPort, int port) throws IOException {
if (client == this && clientPort.getPortNumber() == port) {
throw new IOException("Can't connect a port to its self.");
}
ConnectionStatus permission = hasPermission(clientPort, port);
if (permission == ConnectionStatus.OK) {
int i;
do {
i = (int) (Math.random() * 25536 + 40000); // 2^16 = 65536, 65536 - 40000 = 25536
} while (ports.containsKey(i));
Port defaultServerPort = ports.get(port);
Port hostPort = new Port(defaultServerPort.getProgram(), i, defaultServerPort.getProtocol());
if (hostPort == null) {
throw new IOException(ConnectionStatus.Internal_Server_Error.toString());
}
try {
hostPort.connect(clientPort);
} catch (IOException e) {
e.printStackTrace();
throw new IOException(ConnectionStatus.Service_Unavailable.toString());
}
Connection c = new Connection(this, client, clientPort, hostPort);
connections.put(client.getIp(), c);
client.getConnections().put(ip, c);
return true;
} else {
log("Connection falure", "Connection from: " + client.getIp() + ", to port: " + port);
throw new IOException(permission.toString());
}
}
/**
* Checks if it has permission to make the connection.
*
* @return True if it is allowed.
*/
ConnectionStatus hasPermission(Port port, int hostPort) {
if (!ports.containsKey(hostPort)) {
return ConnectionStatus.Internal_Server_Error;
}
// TODO check server firewall settings, inbound/outbound
return ConnectionStatus.OK;
}
@Override
public final void disconnect(Connection c) {
c.close();
}
@Override
public final void openPort(Port port) throws IOException {
if (!ports.containsKey(port.getPortNumber())) {
ports.put(port.getPortNumber(), port);
return;
}
throw new IOException("Port already exists.");
}
@Override
public final void closePort(int port) throws IOException {
if (!ports.containsKey(port)) {
throw new IOException("Port does not exist.");
}
for (Connection c : connections.values()) { // close connections on the port to be closed.
if (c.getClient() == this && c.getClientPort() == ports.get(port)) {
c.getClientPort().disconnect();
c.getClientPort().disconnect();
c.close();
} else if (c.getHost() == this && c.getHostPort() == ports.get(port)) {
c.getClientPort().disconnect();
c.getClientPort().disconnect();
c.close();
}
}
ports.remove(port);
}
@Override
public final void log(String name, String data) {
try {
log.addFile(new File(name + ".log", data));
} catch (Exception e) {
e.printStackTrace();
}
}
public final void addPart(Part p) {
if (partLimit <= parts.size()) {
return;
}
parts.add(p);
p.setDevice(this);
switch (p.getType()) {
case CPU:
Cpu cpu = (Cpu) p;
if (cpu.getCores() > 0) {
cpuSpeed += cpu.getSpeed() * cpu.getCores() * 0.75; // CPU cores are .75 as efficient than CPUs
} else {
cpuSpeed += cpu.getSpeed();
}
break;
case GPU:
Gpu gpu = (Gpu) p;
gpuSpeed += gpu.getSpeed();
break;
case MEMORY:
Memory memory = (Memory) p;
this.memoryCapacity += memory.getCapacity();
break;
case PART:
Part part = p;
break;
case STORAGE:
Storage storage = (Storage) p;
this.storageCapacity += storage.getCapacity();
break;
}
}
public final void removePart(PartType partType, Part p) {
if (!parts.remove(p)) {
return;
}
switch (partType) {
case CPU:
Cpu cpu = (Cpu) p;
if (cpu.getCores() > 0) {
cpuSpeed -= cpu.getSpeed() * cpu.getCores() * 0.75; // CPU cores are .75 as efficient than CPUs
} else {
cpuSpeed -= cpu.getSpeed();
}
break;
case GPU:
Gpu gpu = (Gpu) p;
gpuSpeed -= gpu.getSpeed();
break;
case MEMORY:
Memory memory = (Memory) p;
this.memoryCapacity -= memory.getCapacity();
break;
case PART:
Part part = p;
break;
case STORAGE:
Storage storage = (Storage) p;
this.storageCapacity -= storage.getCapacity();
break;
}
}
public File getFile(String path) throws FileNotFoundException {
if (path.isEmpty() || !path.matches("^/.*?$")) {
throw new FileNotFoundException();
}
File file = root;
String[] splitPath = path.split("/");
for (String s : splitPath) {
File f = file.getFile(s);
if (f != null) {
file = f;
} else if (!s.isEmpty()) {
throw new FileNotFoundException();
}
}
return file;
}
public int getUsedSpace() {
int space = 0;
for (File f : root.getRecursiveFileList(root)) {
space += f.getSize();
}
return space;
}
public int getTotalSpace() {
int space = 0;
for (Part p : parts) {
if (p instanceof Storage) {
space += ((Storage) p).getCapacity();
}
}
return space;
}
public final void dispose() {
// TODO stop terminal command threads
for (Connection c : connections.values()) {
disconnect(c);
}
for (Port p : ports.values()) {
try {
closePort(p.getPortNumber());
} catch (IOException e) {
e.printStackTrace();
}
}
network.removeDevice(this);
ip = null;
network = null;
}
public enum DeviceType {
DEVICE(), DNS(), SERVER(); // more to come
private DeviceType() {
}
}
// --------getters/setters--------
public File getLogs() {
return logs;
}
public void setLogs(File logs) {
this.logs = logs;
}
public Network getNetwork() {
return network;
}
public int getLevel() {
return level;
}
public Map<Integer, Port> getPorts() {
return ports;
}
public Set<Part> getParts() {
return parts;
}
public void setNetwork(Network network) {
this.network = network;
}
public void setLevel(int level) {
this.level = level;
}
public DeviceType getType() {
return type;
}
public void setType(DeviceType type) {
this.type = type;
}
public Brand getBrand() {
return brand;
}
public void setBrand(Brand brand) {
this.brand = brand;
}
public Model getModel() {
return model;
}
public void setModel(Model model) {
this.model = model;
}
public DeviceScene getDeviceScene() {
return deviceScene;
}
public void setDeviceScene(DeviceScene deviceScene) {
this.deviceScene = deviceScene;
}
public int getMemoryCapacity() {
return memoryCapacity;
}
public void setMemoryCapacity(int memoryCapacity) {
this.memoryCapacity = memoryCapacity;
}
public int getStorageCapacity() {
return storageCapacity;
}
public void setStorageCapacity(int storageCapacity) {
this.storageCapacity = storageCapacity;
}
public HakdSprite getTile() {
return tile;
}
public void setTile(HakdSprite tile) {
this.tile = tile;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public Map<String, Connection> getConnections() {
return connections;
}
public int getCpuSpeed() {
return cpuSpeed;
}
public int getGpuSpeed() {
return gpuSpeed;
}
public int getPartLimit() {
return partLimit;
}
public void setPartLimit(int partLimit) {
this.partLimit = partLimit;
}
public File getRoot() {
return root;
}
public File getSys() {
return sys;
}
public File getHome() {
return home;
}
public File getBin() {
return bin;
}
public File getLog() {
return log;
}
public Vector2 getIsoPos() {
return isoPos;
}
public void setIsoPos(Vector2 isoPos) {
this.isoPos = isoPos;
}
}