package org.bench4q.monitor.performance.linux;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

import org.bench4q.monitor.entiry.LinuxFileRead;
import org.bench4q.monitor.model.LogicalDiskModel;
import org.bench4q.monitor.model.LogicalDiskModelChild;

public class LogicalDiskMonitor extends LinuxFileRead {
	public LogicalDiskMonitor() throws FileNotFoundException {
		super("/proc/diskstats");
		instances = new ArrayList<String>();

		freeSpacePercent = new HashMap<String, Double>();
		freeMegabytes = new HashMap<String, Double>();

		diskTimePercent = new HashMap<String, Double>();
		diskReadTimePercent = new HashMap<String, Double>();
		diskWriteTimePercent = new HashMap<String, Double>();

		averageDiskTransferTimeInSecond = new HashMap<String, Double>();
		averageDiskReadTimeInSecond = new HashMap<String, Double>();
		averageDiskWriteTimeInSecond = new HashMap<String, Double>();

		diskBytesPerSecond = new HashMap<String, Double>();
		diskReadBytesPerSecond = new HashMap<String, Double>();
		diskWriteBytesPerSecond = new HashMap<String, Double>();
		idleTimePercent = new HashMap<String, Double>();

		averageDiskQueueLength = new HashMap<String, Double>();

		currentDiskQueueLength = new HashMap<String, Double>();

	}

	private List<String> instances;

	public List<String> getInstances() throws IOException, InterruptedException {
		getLogicalDiskInfo(1);
		return instances;
	}

	public double getFreeSpacePercent(String instance) throws IOException,
			InterruptedException {
		getLogicalDiskInfo(1);
		return freeSpacePercent.get(instance);
	}

	public double getFreeMegabytes(String instance) throws IOException,
			InterruptedException {
		getLogicalDiskInfo(1);
		return freeMegabytes.get(instance);
	}

	public double getDiskTimePercent(String instance, int idleTime)
			throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return diskTimePercent.get(instance);
	}

	public double getDiskReadTimePercent(String instance, int idleTime)
			throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return diskReadTimePercent.get(instance);
	}

	public double getDiskWriteTimePercent(String instance, int idleTime)
			throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return diskWriteTimePercent.get(instance);
	}

	public double getAverageDiskTransferTimeInSecond(String instance,
			int idleTime) throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return averageDiskTransferTimeInSecond.get(instance);
	}

	public double getAverageDiskReadTimeInSecond(String instance, int idleTime)
			throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return averageDiskReadTimeInSecond.get(instance);
	}

	public double getAverageDiskWriteTimeInSecond(String instacne, int idleTime)
			throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return averageDiskWriteTimeInSecond.get(instacne);

	}

	public double getDiskBytesPerSecond(String instance, int idleTime)
			throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return diskBytesPerSecond.get(instance);
	}

	public double getDiskReadBytesPerSecond(String instance, int idleTime)
			throws IOException, InterruptedException {

		getLogicalDiskInfo(idleTime);
		return diskReadBytesPerSecond.get(instance);
	}

	public double getDiskWriteBytesPerSecond(String instance, int idleTime)
			throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return diskWriteBytesPerSecond.get(instance);
	}

	public double getIdleTimePercent(String instance, int idleTime)
			throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return idleTimePercent.get(instance);
	}

	public double getAverageDiskQueueLength(String instacne, int idleTime)
			throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return averageDiskQueueLength.get(instacne);
	}

	public double getCurrentDiskQueueLength(String instacne, int idleTime)
			throws IOException, InterruptedException {
		getLogicalDiskInfo(idleTime);
		return currentDiskQueueLength.get(instacne);
	}

	private Map<String, Double> freeSpacePercent;
	private Map<String, Double> freeMegabytes;

	private Map<String, Double> diskTimePercent;
	private Map<String, Double> diskReadTimePercent;
	private Map<String, Double> diskWriteTimePercent;

	private Map<String, Double> averageDiskTransferTimeInSecond;
	private Map<String, Double> averageDiskReadTimeInSecond;
	private Map<String, Double> averageDiskWriteTimeInSecond;

	Map<String, Double> diskBytesPerSecond;
	private Map<String, Double> diskReadBytesPerSecond;;
	private Map<String, Double> diskWriteBytesPerSecond;

	private Map<String, Double> idleTimePercent;
	private Map<String, Double> averageDiskQueueLength;
	private Map<String, Double> currentDiskQueueLength;

	public LogicalDiskModel getLogicalDiskInfo(int idleTime)
			throws IOException, InterruptedException {
		LogicalDiskModel logicalDiskModel = new LogicalDiskModel();

		List<String> instances_temp = new ArrayList<String>();
		Map<String, Double> currentDiskQueueLength_p = new HashMap<String, Double>();
		Map<String, Double> currentDiskQueueLength_temp = new HashMap<String, Double>();
		BufferedReader br = this.getBufferedReader();
		String str;
		StringTokenizer token;
		Map<String, Double> readTmie = new HashMap<String, Double>(), writeTime = new HashMap<String, Double>(), readTimes = new HashMap<String, Double>(), writeTimes = new HashMap<String, Double>(), secRead = new HashMap<String, Double>(), secWrite = new HashMap<String, Double>();
		while ((str = br.readLine()) != null) {
			// String s = str;
			token = new StringTokenizer(str);
			str = token.nextToken();

			if (str.equals("8")) {
				// System.out.println(str+":"+s);
				str = token.nextToken();
				if (!(str.equals("0"))) {

					str = token.nextToken();
					String elem = str;
					instances_temp.add(elem);
					str = token.nextToken();
					readTimes.put(elem, (double) Integer.parseInt(str));

					str = token.nextToken();
					str = token.nextToken();
					secRead.put(elem, (double) Integer.parseInt(str));
					// secRead.put(elem, (double) Integer.parseInt(str));
					str = token.nextToken();
					readTmie.put(elem, (double) Integer.parseInt(str));// ms
					str = token.nextToken();
					str = token.nextToken();
					writeTimes.put(elem, (double) Integer.parseInt(str));
					str = token.nextToken();
					secWrite.put(elem, (double) Integer.parseInt(str));
					str = token.nextToken();
					writeTime.put(elem, (double) Integer.parseInt(str));
					str = token.nextToken();
					currentDiskQueueLength_p.put(elem,
							(double) Integer.parseInt(str));
					str = token.nextToken();
					str = token.nextToken();

				}
			}
		}
		br.close();
		Thread.sleep(idleTime);
		br = new BufferedReader(new InputStreamReader(new FileInputStream(
				new File("/proc/diskstats"))));
		while ((str = br.readLine()) != null) {
			token = new StringTokenizer(str);
			str = token.nextToken();
			if (str.equals("8")) {
				str = token.nextToken();
				if (!(str.equals("0"))) {
					str = token.nextToken();
					String elem = str;
					str = token.nextToken();
					readTimes.put(elem,
							(double) (Integer.parseInt(str) - readTimes
									.get(elem)));

					str = token.nextToken();
					str = token.nextToken();
					secRead.put(elem, Integer.parseInt(str) - secRead.get(elem));
					str = token.nextToken();
					readTmie.put(elem,
							Integer.parseInt(str) - readTmie.get(elem));// ms
					str = token.nextToken();
					writeTimes.put(elem,
							Integer.parseInt(str) - writeTimes.get(elem));
					str = token.nextToken();
					str = token.nextToken();
					secWrite.put(elem,
							Integer.parseInt(str) - secWrite.get(elem));
					str = token.nextToken();
					writeTime.put(elem,
							Integer.parseInt(str) - writeTime.get(elem));
					str = token.nextToken();
					currentDiskQueueLength_temp.put(elem,
							(double) Integer.parseInt(str));
					str = token.nextToken();
					str = token.nextToken();
				}
			}
		}

		Runtime rt = Runtime.getRuntime();
		// Integer time = new Integer(idleTime);
		Process p = rt.exec("df -hl ");
		BufferedReader in = new BufferedReader(new InputStreamReader(
				p.getInputStream()));
		while ((str = in.readLine()) != null) {
			token = new StringTokenizer(str);
			str = token.nextToken();
			Iterator<String> itr = instances_temp.iterator();
			while (itr.hasNext()) {
				String instance = itr.next();
				// System.out.println("instance_temp"+instance);
				if (str.contains(instance)) {
					instances.add(instance);

					str = token.nextToken();
					str = token.nextToken();
					freeMegabytes.put(instance, Double.parseDouble(str
							.substring(0, str.length() - 1)) * 1024);
					freeSpacePercent.put(
							instance,
							100 - Double.parseDouble(str.substring(0,
									str.length() - 1)));
					currentDiskQueueLength.put(instance,
							currentDiskQueueLength_temp.get(instance));
				}
			}

		}
		in.close();
		Iterator<String> itr = instances.iterator();
		while (itr.hasNext()) {
			str = itr.next();
			averageDiskQueueLength.put(str,
					(currentDiskQueueLength.get(str) + currentDiskQueueLength_p
							.get(str)) / 2);
			averageDiskTransferTimeInSecond.put(str, (double) idleTime / 1000
					/ (readTimes.get(str) + writeTimes.get(str)));
			if (readTimes.get(str) != 0) {
				averageDiskReadTimeInSecond.put(str, (double) idleTime / 1000
						/ readTimes.get(str));
			} else
				averageDiskReadTimeInSecond.put(str, 0.0);

			if (writeTimes.get(str) != 0) {
				averageDiskWriteTimeInSecond.put(str, (double) idleTime / 1000
						/ writeTimes.get(str));
			} else
				averageDiskWriteTimeInSecond.put(str, 0.0);
			if (readTmie.get(str) != 0) {
				diskReadBytesPerSecond.put(str,
						(double) (secRead.get(str) * 512)
								/ (readTmie.get(str) / 1000));
			} else
				diskReadBytesPerSecond.put(str, 0.0);
			if (writeTime.get(str) != 0) {
				diskWriteBytesPerSecond.put(
						str,
						(double) (secWrite.get(str) * 512)
								/ (writeTime.get(str) / 1000));
			} else
				diskWriteBytesPerSecond.put(str, 0.0);
			if (writeTime.get(str) == 0 && readTmie.get(str) == 0) {
				diskBytesPerSecond.put(str, 0.0);
			} else
				diskBytesPerSecond
						.put(str,
								(double) (secRead.get(str) * 512 + secWrite
										.get(str) * 512)
										/ (readTmie.get(str) / 1000 + writeTime
												.get(str) / 1000));
			idleTimePercent.put(str,
					(double) (100 - (readTmie.get(str) + writeTime.get(str))
							/ idleTime * 100));
			diskTimePercent.put(str, 100 - idleTimePercent.get(str));
			diskReadTimePercent.put(str, (double) readTmie.get(str) / idleTime
					* 100);
			diskWriteTimePercent.put(str, (double) writeTime.get(str)
					/ idleTime * 100);
		}
		itr = instances.iterator();

		while (itr.hasNext()) {
			LogicalDiskModelChild logicalDiskModelChild = new LogicalDiskModelChild();
			String elem = itr.next();

			logicalDiskModelChild.setInstance(elem);
			logicalDiskModelChild.setDiskBytesPerSecond(diskBytesPerSecond
					.get(elem));
			logicalDiskModelChild
					.setDiskWriteBytesPerSecond(diskWriteBytesPerSecond
							.get(elem));

			logicalDiskModelChild
					.setDiskReadBytesPerSecond(diskReadBytesPerSecond.get(elem));
			logicalDiskModelChild
					.setAverageDiskQueueLength(averageDiskQueueLength.get(elem));
			logicalDiskModelChild
					.setAverageDiskReadTimeInSecond(averageDiskReadTimeInSecond
							.get(elem));

			logicalDiskModelChild
					.setAverageDiskTransferTimeInSecond(averageDiskTransferTimeInSecond
							.get(elem));
			logicalDiskModelChild
					.setCurrentDiskQueueLength(currentDiskQueueLength.get(elem));

			logicalDiskModelChild
					.setAverageDiskWriteTimeInSecond(averageDiskWriteTimeInSecond
							.get(elem));

			logicalDiskModelChild.setDiskReadTimePercent(diskReadTimePercent
					.get(elem));
			logicalDiskModelChild.setDiskTimePercent(diskTimePercent.get(elem));
			logicalDiskModelChild.setDiskWriteTimePercent(diskWriteTimePercent
					.get(elem));

			logicalDiskModelChild.setFreeMegabytes(freeMegabytes.get(elem));
			logicalDiskModelChild.setFreeSpacePercent(freeSpacePercent
					.get(elem));
			logicalDiskModelChild.setIdleTimePercent(idleTimePercent.get(elem));

			logicalDiskModel.getLogicalDiskList().add(logicalDiskModelChild);

		}
		br.close();

		return logicalDiskModel;
	}

}
