Index: server/.DS_Store
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: server/.DS_Store
===================================================================
--- server/.DS_Store	(nonexistent)
+++ server/.DS_Store	(revision 13)

Property changes on: server/.DS_Store
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: server/InterfaceServer.java
===================================================================
--- server/InterfaceServer.java	(nonexistent)
+++ server/InterfaceServer.java	(revision 13)
@@ -0,0 +1,13 @@
+package server;
+
+import java.rmi.Remote; 
+import java.rmi.RemoteException;  
+
+// Creating Remote interface for our application 
+public interface InterfaceServer extends Remote {  
+   void backupFile(String path,int replication) throws RemoteException;  
+   void restoreFile(String path) throws RemoteException;
+   void deleteFile(String path) throws RemoteException;
+   void manageLocalStorage(int size) throws RemoteException;
+   void retrieveLocalInformation() throws RemoteException;
+}
\ No newline at end of file
Index: server/Server.java
===================================================================
--- server/Server.java	(nonexistent)
+++ server/Server.java	(revision 13)
@@ -0,0 +1,272 @@
+package server;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.ArrayList;
+import multicastchannels.*;
+import storage.Storage;
+import chunk.*;
+import threads.*;
+
+public class Server implements InterfaceServer {
+	private static String protocolVersion;// Protocol Version
+	private static String serverId;// Server Id
+	private static String serviceAP;// Access Point
+	private static ControlChannel mc;
+	private static BackupChannel mdb;
+	private static RemoteChannel mdr;
+	private static ScheduledThreadPoolExecutor threadLauncher;
+	private String path;
+	private File directory;
+	private static Storage storage;
+
+	public Server(String args[]) throws IOException {
+		// Implement Server constructor
+		threadLauncher = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(250);
+		protocolVersion = args[0];
+		serverId = args[1];
+		serviceAP = args[2];
+
+		// multicast data recovery channel
+		// two arguments -> ip and port
+		mc = new ControlChannel(args[3], Integer.parseInt(args[4]));
+		mdb = new BackupChannel(args[5], Integer.parseInt(args[6]));
+		mdr = new RemoteChannel(args[7], Integer.parseInt(args[8]));
+
+		path = "database/" + serverId;
+
+		directory = new File(path);
+		if (!directory.exists()) {
+			directory.mkdirs();
+			// If you require it to make the entire directory path including parents,
+			// use directory.mkdirs(); here instead.
+		}
+		storage = new Storage();
+
+		
+	}
+
+	public static ControlChannel getmc() {
+		return mc;
+	}
+
+	public static BackupChannel getmdb() {
+		return mdb;
+	}
+
+	public static RemoteChannel getmdr() {
+		return mdr;
+	}
+
+	public static ScheduledThreadPoolExecutor getThreadLauncher() {
+		return threadLauncher;
+	}
+
+	public synchronized void backupFile(String path, int replication) {
+		ChunkFile file = new ChunkFile(path, replication);
+		storage.addFile(file);
+
+		for (int i = 0; i < file.getChunks().size(); i++) {
+
+			Chunk chunk = file.getChunks().get(i);
+
+			chunk.setRepDegree(replication);
+
+			String header = "PUTCHUNK " + protocolVersion + " " + serverId + " " + file.getFileId() + " "
+					+ chunk.getNum() + " " + chunk.getRepDegree() + "\r\n\r\n";
+			System.out.println("SENT" + header);
+
+			String key = file.getFileId() + "." + chunk.getNum();
+
+			if (!storage.getStoredTimes().containsKey(key)) {
+				Server.getStorage().getStoredTimes().put(key, 0);
+			}
+
+			try {
+				byte[] message = createHeader(header, chunk);
+				SendMessage sendThread = new SendMessage(message, "mdb");
+				threadLauncher.execute(sendThread);
+				Thread.sleep(500);
+				Server.getThreadLauncher().schedule(
+						new ManagePutchunk(message, 1, file.getFileId(), chunk.getNum(), replication), 1,
+						TimeUnit.SECONDS);
+
+			} catch (UnsupportedEncodingException | InterruptedException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+
+	private byte[] createHeader(String header, Chunk chunk) throws UnsupportedEncodingException {
+		byte[] asciiHeader, body, message;
+		asciiHeader = header.getBytes(StandardCharsets.US_ASCII);
+		body = chunk.getContent();
+		message = new byte[asciiHeader.length + body.length];
+		System.arraycopy(asciiHeader, 0, message, 0, asciiHeader.length);
+		System.arraycopy(body, 0, message, asciiHeader.length, body.length);
+
+		return message;
+	}
+
+	public void restoreFile(String path) {
+		String filename = null;
+        for (int i = 0; i < storage.getFiles().size(); i++) {
+            if (storage.getFiles().get(i).getPath().equals(path)) {
+                for (int j = 0; j < storage.getFiles().get(i).getChunks().size(); j++) {
+
+                    String header = "GETCHUNK " + protocolVersion + " " + serverId + " " + storage.getFiles().get(i).getFileId() + " " + storage.getFiles().get(i).getChunks().get(j).getNum() + "\r\n\r\n";
+                    System.out.println("Sent " + header);
+
+                    storage.addRemainingChunks(storage.getFiles().get(i).getFileId(), storage.getFiles().get(i).getChunks().get(j).getNum());
+                    filename = new String(storage.getFiles().get(i).getFileId().getBytes(), StandardCharsets.UTF_8);
+                    SendMessage sendThread = new SendMessage(header.getBytes(StandardCharsets.US_ASCII), "mc");
+                }
+                Server.getThreadLauncher().schedule(new ManageRestored(filename), 10, TimeUnit.SECONDS);
+            } else System.out.println("ERROR: File was never backed up.");
+        }
+	}
+
+	
+
+	public void deleteFile(String path) {
+		for (int i = 0; i < storage.getFiles().size(); i++) {
+			if (storage.getFiles().get(i).getPath().equals(path)) {
+
+				for (int j = 0; j < 10; j++) {
+					String header = "DELETE " + protocolVersion + " " + serverId + " "+ storage.getFiles().get(i).getFileId() + "\r\n\r\n";
+					System.out.println("Send DELETE " + header);
+					SendMessage sendThread = new SendMessage(header.getBytes(StandardCharsets.US_ASCII), "mc");
+					threadLauncher.execute(sendThread);
+				}
+				for (int j = 0; j < storage.getFiles().get(i).getChunks().size(); j++) {
+					storage.removeStoredOccurrencesEntry(storage.getFiles().get(i).getFileId(), storage.getFiles().get(i).getChunks().get(j).getNum());
+				}
+				storage.getFiles().remove(i);
+				break;
+			}
+		}
+
+	}
+
+	public void manageLocalStorage(int size) {
+
+		System.out.println("Specify the maximum disk space used(0 to reclaim all dispace allocated by the server): ");
+	}
+
+	private static void deserializeStorage() {
+		try {
+			String filename = "database/" + Server.getServerId() + "/storage.txt";
+
+			File file = new File(filename);
+			if (!file.exists()) {
+				storage = new Storage();
+				return;
+			}
+
+			FileInputStream fileIn = new FileInputStream(filename);
+			ObjectInputStream in = new ObjectInputStream(fileIn);
+			storage = (Storage) in.readObject();
+			in.close();
+			fileIn.close();
+		} catch (IOException i) {
+			i.printStackTrace();
+		} catch (ClassNotFoundException c) {
+			System.out.println("Storage class not found");
+			c.printStackTrace();
+		}
+	}
+
+	public void retrieveLocalInformation() {
+		
+
+		System.out.println("Esta a funcionar -Local Info");
+	}
+
+	public int getVersion() {
+		return Integer.parseInt(protocolVersion);
+	}
+
+	public static String getServerId() {
+		return serverId;
+	}
+
+	public String getAccessProtocol() {
+		return serviceAP;
+	}
+
+	public ControlChannel getControlChannel() {
+		return mc;
+	}
+
+	public BackupChannel getBackupChannel() {
+		return mdb;
+	}
+
+	public RemoteChannel getRemoteChannel() {
+		return mdr;
+	}
+
+	public static Storage getStorage() {
+		return storage;
+	}
+
+	private static void serializeStorage() {
+		try {
+			String filename = "database/" + Server.getServerId() + "/storage.txt";
+
+			File file = new File(filename);
+			if (!file.exists()) {
+				file.getParentFile().mkdirs();
+				file.createNewFile();
+			}
+
+			FileOutputStream fileOut = new FileOutputStream(filename);
+			ObjectOutputStream out = new ObjectOutputStream(fileOut);
+			out.writeObject(storage);
+			out.close();
+			fileOut.close();
+		} catch (IOException i) {
+			i.printStackTrace();
+		}
+	}
+
+	public static void main(String args[]) {
+		try {
+			if (args.length != 9) {
+				System.out.println(
+						"ERROR INVALID ARGUMENTS: Server <versionId> <serviceId> <ser_access_point> <mc_ip> <mc_port> <mdb_ip> <mdb_port> <mdr_ip> <mdr_port>");
+			}
+			// Instantiating the implementation class
+			Server server = new Server(args);
+			// Exporting the object of implementation class
+			// (here we are exporting the remote object to the stub)
+
+			InterfaceServer stub = (InterfaceServer) UnicastRemoteObject.exportObject(server, 0);
+
+			// Binding the remote object (stub) in the registry
+			Registry registry;
+			try {
+				registry = LocateRegistry.createRegistry(1099);
+			} catch (Exception e) {
+				registry = LocateRegistry.getRegistry();
+
+			}
+
+			registry.bind(server.serviceAP, stub);
+
+			System.err.println("Server ready");
+		} catch (Exception e) {
+			System.err.println("Server exception: " + e.toString());
+			e.printStackTrace();
+		}
+		deserializeStorage();
+		Runtime.getRuntime().addShutdownHook(new Thread(Server::serializeStorage));
+	}
+
+}
\ No newline at end of file
