package taskspaces.system;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * This class is used by the Logging system to retrieve logs outputted by nodes and spaces.
 * It is typically sent to them via the LogHopper which runs on the code server.
 * The LogAgent is sent to Nodes and Spaces by the LogHopper.
 * @author Matthew Keoshkerian
 * @version 2.0
 */
public class LogAgent extends Agent implements Runnable
{
	/** The socket of the LogHopper. */
	Socket socket;
	
	/** The instance of the initializing class. */
    Object inst;

    /**
     * Default constructor
     */
    public LogAgent()
    {
    }

    /**
     * Method to set the variables necessary for communication.
     * @param socket socket connection to the LogHopper
     * @param inst the instance of the object which recieved the LogAgent and initialized it.
     * @return void
     */
    public void setVars(Socket socket, Object inst)
    {
    	this.socket = socket;
    	this.inst = inst;
    }
    
    
    /**
     * This method is executed by the Node upon being recieved.
     * Inherited by the Runnable Interface.
     * @return void
     */
    public void run()
    {
    	// Grab the Output Stream of the socket.
    	OutputStream outstream = null;
    	ObjectOutputStream out = null;
    	
    	try {
    		outstream = socket.getOutputStream();
    		out = new ObjectOutputStream(outstream);
	
	
    		// Now we must find all the logs. Place the list of logs into an array.
    		File logDir = new File ("./logs/");
    		File [] logFiles = logDir.listFiles();
    		int length = logFiles.length;
    		System.out.println(length);
	    
    		// Create a new directory for backup logs.
    		File backLogs = new File ("./logs/backup");
    		backLogs.mkdir();
	    
    		loop:for (int i = 0; i < length; i++)
    		{
    			// Place the file refrence onto the local stack to avoid multiple array calls.
    			File file = logFiles[i];
    			//System.out.println(file);
	    
    			// Grab the file name, tokenize it, and then store the username and application name
    			String fileName = file.getName();
    			// System.out.println(fileName);
    			StringTokenizer userApp = new StringTokenizer(fileName, ".");

    			if(fileName.equals("backup"))
    			{
    				// In this case, it is merely the backup folder. These logs are not desired.
    				continue loop;
    			}

    			// Recieve the username and the application name from the tokenized filename.
    			String user = userApp.nextToken();
    			String appName = userApp.nextToken();
	    
    			// Send the log file
    			//System.out.println("Sending over the log");
    			sendLog(out, file, user, appName);
		
    			// Backup the log file now.
    			String orgFilename = file.getName();
    			Calendar date = Calendar.getInstance();
    			int day = date.get(Calendar.DAY_OF_MONTH);
    			int month = date.get(Calendar.MONTH);
    			int year = date.get(Calendar.YEAR);
    			int hour = date.get(Calendar.HOUR);
    			int minute = date.get(Calendar.MINUTE);
    			int second = date.get(Calendar.SECOND);
    			String newFilename = day + month + year + hour + minute + second + "-" + orgFilename;
		
    			file.renameTo(new File("./logs/backup/"+newFilename));
    			
    			/*if(inst instanceof Space)
    			{
    			}
    			else if(inst instanceof Node)
    			{
    			}
    			else if(inst instanceof Task)
    			{
    			}*/
		 
    		}
	    
    		//System.out.println("All the log files have been sent... LogAgent going down...");
    		// Send the Termination signal. This happens after all the logs are sent.
    		out.writeInt(0);
    		out.flush();
	
    		//System.out.println("Notified LogHopper... Going donwn...");
    		// Close the streams and socket.
    		out.close();
    		outstream.close();
    		socket.close();
    		//System.out.println("Socket and streams closed.");
    	}
    	catch (IOException e)
		{
    		e.printStackTrace();
		}
    	catch(NullPointerException e)
		{
    		// Instruct the Hopper there is nothing here
    		//System.out.println("The folder was not found. Instructing the LogHopper");
    		e.printStackTrace();
    		try {
    			out.writeInt(0);
    			out.flush();
    			out.close();
    			outstream.close();
    			socket.close();
    		}
    		catch(Exception f) { f.printStackTrace(); }
    		//System.out.println("Instruction sent. Socket and streams closed.");
		}

    }
    
    /**
     * This method attempts to read the log and sends the raw bytes of the file over the stream.
     * This version of the method is designed for system admin logs ONLY. It calls the main sendLog with "system"/"system".
     * It is the same as calling <code>sendLog (outstream, filename, user, appName);</code>
     * @param outstream The OutputStream of the socket connection to send the file over
     * @param f The file object corresponding to the log file.
     * @return <code>true</code> if the file was successfully sent, <code>false</code> if otherwise.
     */
    public boolean sendLog (ObjectOutputStream outstream, File f)
    {
    	// Send Log using sendLog and the user/app of system/system
    	return sendLog(outstream, f, "system", "system");
    }

    /**
     * This method attempts to read the log and sends the raw bytes of the file over the stream.
     * This version of the method is the main version.
     * @param outstream The OutputStream of the sucket connection to send the file over
     * @param f The file object corresponding to the log file.
     * @param user The username two which the logs are to be sent to
     * @param appName The application name this log monitors
     * @return <code>true</code> if the file was successfully sent, <code>false</code> if otherwise.
     */
    public boolean sendLog (ObjectOutputStream outstream, File f, String user, String appName)
    {
    	// Check to see if the file exists, then proceed.
    	if (f.exists())
    	{
    		try {
    			// The file exists, send a message back through the stream indicating it is to be sent.
    			ObjectOutputStream out = outstream;
    			if (user.equals("system"))
    				out.writeInt(1);           // 1 means system log is waiting to be sent
    			else
    			{
    				out.writeInt(2);           // 2 means anyone's log is waiting to be sent
    				out.writeObject(user);     // Send the username
    				out.writeObject(appName);  // Send the appName
    			}
    			out.flush();
	    
    			// Send the file in bytes back to the LogHopper.
    			FileInputStream fis = new FileInputStream(f);
    			//BufferedOutputStream data = new BufferedOutputStream(outstream);
    			int b;
    			//System.out.println("Writing");
    			while ((b=fis.read())!=-1) { out.writeInt(b); /*System.out.println(b);*/ }
    			//System.out.println("Writing done...");
    			out.writeInt(-1);
    			//System.out.println("Instruction for termination sent...");
    			out.flush();
    			fis.close();
    		}
    		catch(IOException e)
			{
    			return false;
    			//e.printStackTrace();
			}
    		return true;
    	}
    	return false;
    }
}
