package rdms;

import rdms.Meter;
import rdms.MeterRead;
import rdms.RunnableThread;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Properties;

import com.toshiba.mwcloud.gs.Collection;
import com.toshiba.mwcloud.gs.GSException;
import com.toshiba.mwcloud.gs.GridStore;
import com.toshiba.mwcloud.gs.GridStoreFactory;
import com.toshiba.mwcloud.gs.Query;
import com.toshiba.mwcloud.gs.RowSet;

import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ThreadManager {
	ArrayList<RunnableThread> threads;
	
	private int gOrM; // 1 for mysql, 2 for griddb
	private int stopN;
	private boolean stopForTest;
	private int secWait;
	
	boolean canStart = true;
	boolean canEnd = false;
	
	Date startTime;
	Date endTime;
	
	private int num1;
	
	private RunnableThread tempThread;
	
	boolean hasMeter = false;
	boolean hasMeterRead = false;
	Meter meter1;
	MeterRead meterRead1;
	private ArrayList<Long> idsN;
	
	GridStore server;
	boolean isSet = false;
	
	Connection serverSQL;
	boolean isSet2;
	
	
	int option = 0;
	
	int mins = 1;
	
	private Query<Meter> meterQuery;
	private RowSet<Meter> meterRows;
	private Collection<String,Meter> metersCol;
	private String indexName2 = "METERS";
	//
	Properties sourceProps = new Properties();
	//
	private static String serverName = "griddb1";
	private static String port = "3306";
	private static String username = "testuser1";
	private static String password = "Admin1!!!";
	
	private static String db = "testdb";
	
	private static String url1 = "jdbc:mysql://" + serverName + ":" + port + "/";
	
	private static String timezoneStuff = "?useUnicode&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";

	private static String fullURL1 = url1 + db + timezoneStuff;
	//
	private void connectMySQL() {
		System.out.println("Attempting to connect...");
		try {
			try {
				Class.forName("com.mysql.cj.jdbc.Driver");
			} catch (ClassNotFoundException e) {
				System.out.println("Can't find Driver");
				e.printStackTrace();
			}
			
			serverSQL = DriverManager.getConnection(fullURL1, username, password);
			System.out.println("Successfully Connected");
		} catch (SQLException e) {
			System.out.println("Failed Connection");
			e.printStackTrace();
		} 
	}
	private void connectGridDB() {
		InputStream input;
		boolean debug = true;
		boolean worked = false;
		try {
			input = new FileInputStream("rdms/source.properties");
			sourceProps.load(input);
		} catch (Exception e) {
			System.out.println("COULD NOT LOAD source.properties");
		}
		if(debug) {
			System.out.println("SOURCE PROPS:");
			System.out.println(sourceProps);
		}
		try {
			server = GridStoreFactory.getInstance().getGridStore(sourceProps);
			worked = true;
		} catch (GSException e) {
			System.out.println("Could not connect to GridDB");
			e.printStackTrace();
		}
		if(debug && worked)
			System.out.println("Connected to GridDB!");
		
	}
	private void endConnectionGridDB() {
		try {
			server.close();
		} catch (GSException e) {
			System.out.println("Could not close server");
			e.printStackTrace();
		}
	}
	private void endConnectionMySQL() {
		try {
			serverSQL.close();
			System.out.println("Closed connection successfully");
		} catch (SQLException e) {
			System.out.println("Failed to close connection");
			e.printStackTrace();
		}
	}
	private void setUp1() {
		try {
			metersCol = server.putCollection(indexName2, Meter.class);
			meterQuery = metersCol.query("select * ");
			meterRows = meterQuery.fetch(false);
			metersCol.setAutoCommit(false);
		} catch (GSException e) {
			e.printStackTrace();
		}
	}
	
	public ThreadManager() {
		gOrM = 1;
		stopN = 0;
		stopForTest = true;
		secWait = 60;
		threads = new ArrayList<RunnableThread>();
		idsN = new ArrayList<Long>();
	}
	
	public void setMinutes(int minutes) {
		mins = minutes;
	}
	
	public ThreadManager(boolean mySQL, boolean gridDB) {
		if(mySQL && gridDB) {
			gOrM = 0;
		}
		else if(mySQL) {
			gOrM = 1;
		}
		else if(gridDB) {
			gOrM = 2;
		}
		stopN = 0;
		stopForTest = true;
		secWait = 60;
		threads = new ArrayList<RunnableThread>();
	}
	
	public void setStopNum(int n) {stopN = n;}
	public void setStopForTest(boolean b) {stopForTest = b;}
	public void setSecondsWait(int s) {secWait = s;}
	public void setGridOrMySQL(int o) {gOrM = o;}
	
	public void setOption(int op) {
		option = op;
	}
	public int getOption() {
		return option;
	}
	
	public RunnableThread getRunThread() {
		return tempThread;
	}
	public void setMeter(Meter m) {
		meter1 = m;
		hasMeter = true;
	}
	public void setMeterRead(MeterRead mr) {
		meterRead1 = mr;
		hasMeterRead = true;
	}
	public void genereateIDs(long start, long interval, int num) {
		
		for(int i = 0; i < num; i++) {
			long curID = start + (i * interval);
			idsN.add(curID);
		}
	}
	public void startThreads(int num) {
		String nameType;
		int numCount = 0;
		long tempId;
		num1 = num;
		if(canStart) {
			startTime = new Date();
			canStart = false;
		}
		if(gOrM == 1) {
			nameType = "MySQLThread";
			if(isSet2 == false) {
				connectMySQL();
				isSet2 = true;
			}
		} else if(gOrM == 2) {
			nameType = "GridDBThread";
			if(isSet == false) {
				connectGridDB();
				setUp1();
				isSet = true;
			}
		} else {
			nameType = "ThreadNotSpecified";
		}
		for(int i = 0; i < num; i++) {
			String tempName = nameType + "-" + i;
			RunnableThread tempR = new RunnableThread(tempName,gOrM);
			tempR.setOption(option);
			tempR.setMins(mins);
			tempR.setSeconds(secWait);
			if(isSet && gOrM == 2) {
				tempR.setGridServer(server);
				tempR.setUp2(metersCol, meterRows, meterQuery);
			} else if(isSet2 && gOrM == 1) {
				tempR.setSQLServer(serverSQL);
			}
			tempR.setStopForTest(stopForTest);
			tempR.setStopNum(stopN);
			if(hasMeter) {
				tempId = idsN.get(i);
				meter1.id = tempId;
				tempR.setMeter(meter1);
			}
			if(hasMeterRead) {
				tempR.setMeterRead(meterRead1);
			}
			threads.add(tempR);
			if(numCount == 0) {
				tempThread = tempR;
			}
			tempR.start();
		}
	}
	public boolean checkThreads() {
		for(int i = 0; i < num1; i++) {
			boolean tr = threads.get(i).isEnded();
			if(!tr) {
				return false;
			}
		}
		try {
			if(gOrM == 2)
				endConnectionGridDB();
			else if(gOrM == 1)
				endConnectionMySQL();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
		}
		return true;
	}
	public Date getStartTime() {
		return startTime;
	}
	public Date getEndTime() {
		Date prior = threads.get(0).getEndTime();
		endTime = prior;
		for(int i = 1; i < num1; i++) {
			Date now = threads.get(i).getEndTime();
			if(now.after(prior)) {
				endTime = now;
			}
		}
		return endTime;
	}
}