package pulling.availability_predection;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.StringTokenizer;
import java.util.Random;

/**
 * This class represents the concept of system usage
 * in terms of CPU. It is used to read the CPU usage. 
 * 
 * IMPORTANT: When run on windows the program does not
 * include functions for System Percentage or User Percentage
 *
 * @author Ben Kybartas & Majd Kokaly
 * @version 1
 *
 */
public class CPU_Usage implements Serializable {
	/**
	 * The serialVersionUID is used to universally identify this version of this
	 * class.
	 */
	private static final long serialVersionUID = -2436410526741845722L;
	

	
	/**
	 * The default value passed to the command sar as the second argument.
	 * It is the number of time the sar utility reads the CPU usage
	 */
	final private int TIMES_CHECKED = 3;
	
	/**
	 * The default value passed to the command sar as the first argument.
	 * It is the seconds between every reading performed by the sar command.
	 */
	final private int PERIODS_IN_SECONDS = 1;
	
	/**
	 * The user percentage from the last reading.
	 * Every CPU reading gives three readings; a reading for the user usage, another for the system usage and one for the idle percentage
	 */
	private int usersPercentage;
	
	/**
	 * The system percentage from the last reading.
	 * Every CPU reading gives three readings; a reading for the user usage, another for the system usage and one for the idle percentage
	 */
	private int systemPercentage;
	
	/**
	 * The idle percentage from the last reading.
	 * Every CPU reading gives three readings; a reading for the user usage, another for the system usage and one for the idle percentage
	 */
	private int idlePercentage;
	
	private Random r = new Random();
	
	/**
	 * This constructor execute the sar command and set the usersPercentage, systemPercentage and the idlePercentage accordingly.
	 * @throws Exception When the command sar is not properly executed.
	 */
	public CPU_Usage() throws Exception { // a CPU_Usage Object with the current utilization is created
		/*int idlepercent;
		idlepercent = 95 + r.nextInt(5);
		this.setIdlePercentage(100);*/
		
		StringTokenizer tokenizer;
		Runtime runtime = Runtime.getRuntime();
		// With the defualt values this take 3 seconds
		Process proc = null;
		String os = System.getProperty("os.name");
		
		if (os.equalsIgnoreCase("Linux"))
		{
			proc = runtime.exec("vmstat 1 2");
		}
		else if (os.startsWith("Windows"))
		{
			proc = runtime.exec("Typeperf \"\\Processor(_Total)\\% Idle Time\"");
		}
		else 
		{
			proc = runtime.exec("sar -u " + PERIODS_IN_SECONDS + " " + TIMES_CHECKED);
		}
		
		InputStream inputstream = proc.getInputStream();
		InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
		BufferedReader bufferedreader = new BufferedReader(inputstreamreader); // bufferreader is a buffer of the input
		String line;
		
		if (os.startsWith("Windows"))
		{
			int i = 0;
			String SystemIdle;
			while ((line = bufferedreader.readLine()) != null && i < 3)
			{
				i++;
			}	
			proc.destroy();
			tokenizer = new StringTokenizer(line, ",");
			tokenizer.nextToken();
			SystemIdle = tokenizer.nextToken();
			SystemIdle = SystemIdle.substring(1, SystemIdle.length() - 1);
			this.setIdlePercentage((int) Double.parseDouble(SystemIdle));
			return;
		}
		
		else if (os.startsWith("Linux"))
		{
			int i = 0;
			
			while ((line = bufferedreader.readLine()) != null && i < 3)
			{
				i++;
			}
			
			tokenizer = new StringTokenizer(line);
			
			for (int j = 0; j < 12; j++)
			{
				tokenizer.nextToken();
			}
			this.setUsersPercentage(Integer.parseInt(tokenizer.nextToken()));
			this.setSystemPercentage(Integer.parseInt(tokenizer.nextToken()));
			this.setIdlePercentage(Integer.parseInt(tokenizer.nextToken()));
			
		}
		else
		{
			while ((line = bufferedreader.readLine()) != null) 
			{
				if (line.trim().length() > 3 && line.trim().substring(0,7).toLowerCase().equalsIgnoreCase("average") ) 
				{
					tokenizer = new StringTokenizer(line);
					tokenizer.nextToken();
					this.setUsersPercentage(Integer.parseInt(tokenizer.nextToken()));
					if (System.getProperty("os.version").startsWith("10.5.")) // To ignore the %nice entry when executing on Mac OS X version 10.5 (Leopard)
						tokenizer.nextToken();
					this.setSystemPercentage(Integer.parseInt(tokenizer.nextToken()));
					this.setIdlePercentage(Integer.parseInt(tokenizer.nextToken()));
					return;
				}
			}	
		}

	}
	
	
	/**
	 * This constructor execute the sar command with seconds and times argument passed to it and then set the usersPercentage, systemPercentage and the idlePercentage accordingly.
	 * @throws Exception When the command sar is not properly executed.
	 */
	public CPU_Usage(int seconds, int times) throws Exception { // a CPU_Usage Object with the current utilization is created
		StringTokenizer tokenizer;
		Runtime runtime = Runtime.getRuntime();
		// With the default values this take 3 seconds
		Process proc = null;
		String os = System.getProperty("os.name");
		
		if (os.equalsIgnoreCase("Linux"))
		{
			proc = runtime.exec("sar " + seconds + " " + times + " -u");
		}
		else if (os.startsWith("Windows"))
		{
			proc = runtime.exec("Typeperf \"\\Processor(_Total)\\% Idle Time\"");
		}
		else 
		{
			proc = runtime.exec("sar -u " + seconds + " " + times);
		}
		
		InputStream inputstream = proc.getInputStream();
		InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
		BufferedReader bufferedreader = new BufferedReader(inputstreamreader); // bufferedreader is a buffer of the input
		String line;

		
		if (os.startsWith("Windows"))
		{
			int i = 0;
			String SystemIdle;
			while ((line = bufferedreader.readLine()) != null && i < 3)
			{
				i++;
			}	
			proc.destroy();
			tokenizer = new StringTokenizer(line, ",");
			tokenizer.nextToken();
			SystemIdle = tokenizer.nextToken();
			SystemIdle = SystemIdle.substring(1, SystemIdle.length() - 1);
			this.setIdlePercentage((int) Double.parseDouble(SystemIdle));
			return;
		}
		
		while ((line = bufferedreader.readLine()) != null) 
		{
			if (line.trim().length() > 3 && line.trim().substring(0,7).toLowerCase().equalsIgnoreCase("average") ) 
			{
				tokenizer = new StringTokenizer(line);
				tokenizer.nextToken();
				
				if (os.equalsIgnoreCase("Linux"))
				{
					tokenizer.nextToken();
					this.setUsersPercentage((int) Double.parseDouble(tokenizer.nextToken()) );
					tokenizer.nextToken();
					this.setSystemPercentage((int) Double.parseDouble(tokenizer.nextToken()) );
					tokenizer.nextToken();
					tokenizer.nextToken();
					this.setIdlePercentage((int) Double.parseDouble(tokenizer.nextToken()) );
				}
				else
				{
					this.setUsersPercentage(Integer.parseInt(tokenizer.nextToken()) );
					if (System.getProperty("os.version").startsWith("10.5.")) // To ignore the %nice entry when executing on Leopard
						tokenizer.nextToken();
					this.setSystemPercentage(Integer.parseInt(tokenizer.nextToken()) );
					this.setIdlePercentage(Integer.parseInt(tokenizer.nextToken()) );
				}
				return;
			}
		}	
	}
	
	
	
	public int getUsersPercentage() {
		return usersPercentage;
	}
	public void setUsersPercentage(int usersPercentage) {
		this.usersPercentage = usersPercentage;
	}
	
	public int getSystemPercentage() {
		return systemPercentage;
	}
	public void setSystemPercentage(int systemPercentage) {
		this.systemPercentage = systemPercentage;
	}
	
	public int getIdlePercentage() {
		return idlePercentage;
	}
	public void setIdlePercentage(int idlePercentage) {
		this.idlePercentage = idlePercentage;
	}
	
	public void print () {
		System.out.print("Users: " + this.getUsersPercentage() + " ,System: " + this.getSystemPercentage() + " ,Idle: " + this.getIdlePercentage() );
		
	}
	
	/**
	 * 
	 * @return the current system idle percentage
	 */
	public static int getSystemIdlePercentage() {
		try {
			CPU_Usage usage = new CPU_Usage();
			return  usage.getIdlePercentage();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return 0;
	}
	
	/**
	 * 
	 * @param seconds
	 * @param times
	 * @return the current system idle percentage after passing times and seconds to sar command
	 */
	public static int getSystemIdlePercentage(int seconds, int times) {
		try {
			CPU_Usage usage = new CPU_Usage(seconds, times);
			return  usage.getIdlePercentage();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return 0;
	}
	
	
	
}


