package rdms;

import rdms.Extract;
import rdms.Meter;
import rdms.MeterRead;
//import rdms.ServerConnection;

import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.TimeZone;

import com.toshiba.mwcloud.gs.Aggregation;
import com.toshiba.mwcloud.gs.AggregationResult;
import com.toshiba.mwcloud.gs.Collection;
import com.toshiba.mwcloud.gs.Container;
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 com.toshiba.mwcloud.gs.TimeSeries;
import com.toshiba.mwcloud.gs.TimestampUtils;

public class GridDBExtract extends Extract {
	
	private String indexName2 = "METERS";
	private String indexName1 = "METER_READS";
	
	private Collection<String,Meter> metersCol;
	private HashMap<String,MeterRead> dataMap;
	
	private Query<Meter> meterQuery;
	private RowSet<Meter> meterRows;
	//
	Properties sourceProps = new Properties();
	GridStore store;
	//
	private void setUp() {
		try {
			metersCol = store.putCollection(indexName2, Meter.class);
			dataMap = new HashMap<String,MeterRead>();
			meterQuery = metersCol.query("select * ");
			meterRows = meterQuery.fetch(false);
			metersCol.setAutoCommit(false);
		} catch (GSException e) {
			e.printStackTrace();
		}
	}
	//
	@Override
	public void clearDatabase() {
		boolean debug = true;
		RowSet<Meter> meterRows1;
		for(int i = 0; i < 100; i++) {
			try {
				store.dropTimeSeries(indexName1 + "_" + i);
			} catch(GSException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
		try {
			meterRows1 = meterQuery.fetch(false);
			while(meterRows1.hasNext()) {
				Meter tempM = meterRows1.next();
				store.dropTimeSeries(indexName1 + "_" + tempM.id);
				if(debug) System.out.println("Deleted " + indexName1 + "_" + tempM.id);
			}
		} catch (GSException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		try {
			store.dropCollection(indexName1);
			if(debug) System.out.println("Dropped collection " + indexName1);
			store.dropCollection(indexName2);
			if(debug) System.out.println("Dropped collection " + indexName2);
		} catch(GSException e) {
			System.out.println("Failed to delete collection");
			e.printStackTrace();
		}
	}
	@Override
	public float calculateUsageMonth(long id, int monthnum) {
		int month = monthnum - 1;
		
		float result = 0;
		/*
		*/
		Calendar calstart = Calendar.getInstance();
		Calendar calend = Calendar.getInstance();
		//
		// Setting beginning and end dates for calendar
			// Setting month of what we want to retrieve
		calstart.set(Calendar.MONTH, month);
		calend.set(Calendar.MONTH, month);
			// Setting the day that we want to retrieve. We set the day for calend to 0 to get the last day of the month, after adding the month (because it subtracts from the beginning)
		calstart.set(Calendar.DAY_OF_MONTH, 1);
		calend.add(Calendar.MONTH, 1);
		calend.set(Calendar.DAY_OF_MONTH, 0);
			// Setting the hour/minute/second
		calend.set(Calendar.HOUR_OF_DAY,23);
		calend.set(Calendar.MINUTE, 59);
		calend.set(Calendar.SECOND, 59);
		calstart.set(Calendar.HOUR_OF_DAY,0);
		calstart.set(Calendar.MINUTE, 0);
		calstart.set(Calendar.SECOND, 0);
		//
		System.out.println("Start: " + calstart.getTime().toString());
		System.out.println("End: " + calend.getTime().toString());
			// format the dates to the format that will be used in griddb
		String endMonthF = TimestampUtils.format(calend.getTime());
		String startMonthF = TimestampUtils.format(calstart.getTime());
			// create the command queries
		String commandT = "SELECT SUM(usage_since_read) WHERE timestamp < TIMESTAMP(\'" + endMonthF +"\') AND timestamp > TIMESTAMP(\'"
				+ startMonthF + "\')";
		String commandT1 = "SELECT MAX(usage_this_month) WHERE timestamp < TIMESTAMP(\'" + endMonthF +"\') AND timestamp > TIMESTAMP(\'"
				+ startMonthF + "\')";
			// Attempt to extract the result from the database
		try {
			//
			//System.out.println(commandT);
			//
			TimeSeries<MeterRead> tempSeries = store.getTimeSeries(indexName1 + "_" + id, MeterRead.class);
			double result1 = tempSeries.query(commandT, AggregationResult.class).fetch().next().getDouble();
			//
			double result2 = tempSeries.query(commandT1, AggregationResult.class).fetch().next().getDouble();
			System.out.println("Max: " + ((float) result2));
			//
			result = (float) result1;
			return result;
		} catch (GSException e) {
			// TODO Auto-generated catch block
			return (float) 0;
			//e.printStackTrace();
		}
		
		//connection.getServerGridDB().get(indexName1 + "_" + tempMeter.id, arg1)
		//return result;
	}
	public void testFunction() {
		int month = 7;
		float test = calculateUsageMonth((long)1,(month - 1));
		System.out.println("Sum: " + test);
	}
	//
	@Override
	public void connectToServer() {
		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 {
			store = GridStoreFactory.getInstance().getGridStore(sourceProps);
			worked = true;
		} catch (GSException e) {
			// TODO Auto-generated catch block
			System.out.println("Could not connect to GridDB");
			e.printStackTrace();
		}
		if(debug && worked)
			System.out.println("Connected to GridDB!");
		//connection.setServerGridDB();
		setUp();
	}
	// I should try to improve the performance here, if possible
	@Override
	public void gatherData() {
		Meter tempMeter;
		TimeSeries<MeterRead> tempSeries;
		Query<MeterRead> tempQuery;
		RowSet<MeterRead> tempRows;
		MeterRead tempMeterRead;
		//
		HashSet<MeterRead> tempSet = new HashSet<MeterRead>();
		//
		try {
			while(meterRows.hasNext()) {
				tempMeter = new Meter();
				tempMeter = meterRows.next();
				//
				super.meterList.add(tempMeter);
				//
				long tempID = tempMeter.id;
				//
				tempSeries = store.getTimeSeries(indexName1 + "_" + tempMeter.id, MeterRead.class);
				tempSeries.setAutoCommit(false);
				tempQuery = tempSeries.query("select * ");
				tempRows = tempQuery.fetch(false);
				try {
					while(tempRows.hasNext()) {
						tempMeterRead = tempRows.next();
						//
						//System.out.println("asdasd " + tempMeterRead.all_time_usage);
						//
						super.meterReadList.add(tempMeterRead);
						if(super.mappedList.containsKey(tempID) && !super.mappedList.get(tempID).isEmpty()) {
							tempSet = super.mappedList.get(tempID);
							tempSet.add(tempMeterRead);
						} else {
							tempSet = new HashSet<MeterRead>();
							tempSet.add(tempMeterRead);
						}
						super.mappedList.put(tempID, tempSet);
					}
				} catch (Exception e1) {
					System.out.println("FAILED TO GET ROW METER_READ DATA");
				}
			}
		} catch(Exception e) {
			System.out.println("FAILED TO GET METER DATA");
		}
	}
	@Override
	public void closeServer() {
		//connection.closeServerGridDB();
		try {
			store.close();
		} catch (GSException e) {
			// TODO Auto-generated catch block
			System.out.println("Could not close server");
			e.printStackTrace();
		}
	}
	@Override
	public void printData() {
		Meter tempMeter;
		TimeSeries<MeterRead> tempSeries;
		Query<MeterRead> tempQuery;
		RowSet<MeterRead> tempRows;
		MeterRead tempMeterRead;
		try {
			System.out.println("Meter Size: " + meterRows.size());
			System.out.println("____METERS INDEX____");
			while(meterRows.hasNext()) {
				tempMeter = meterRows.next();
				System.out.println("      ____METER____");
				System.out.println("      ID: " + tempMeter.id);
				System.out.println("      Name: " + tempMeter.contact_name);
				System.out.println("      Email: " + tempMeter.email);
				System.out.println("      Number: " + tempMeter.phone_number);
				System.out.println("      Description: " + tempMeter.description);
				System.out.println("      Address: " + tempMeter.address);
				System.out.println("      City: " + tempMeter.city);
				System.out.println("      State OR Province: " + tempMeter.state_province);
				System.out.println("      Last Reading: " + tempMeter.last_reading);
				System.out.println("      Latitude: " + tempMeter.latitude);
				System.out.println("      Longitude: " + tempMeter.longitude);
				tempSeries = store.getTimeSeries(indexName1 + "_" + tempMeter.id, MeterRead.class);
				tempSeries.setAutoCommit(false);
				tempQuery = tempSeries.query("select * ");
				tempRows = tempQuery.fetch(false);
				try {
					while(tempRows.hasNext()) {
						tempMeterRead = tempRows.next();
						System.out.println("            ---Meter_Read---");
						System.out.println("                  Timestamp:" + tempMeterRead.timestamp);
						System.out.println("                  Usage Since Read:" + tempMeterRead.usage_since_read);
						System.out.println("                  Usage This Day:" + tempMeterRead.usage_this_day);
						System.out.println("                  Usage This Week:" + tempMeterRead.usage_this_week);
						System.out.println("                  Usage This Month:" + tempMeterRead.usage_this_month);
						System.out.println("                  Usage This Year:" + tempMeterRead.usage_this_year);
						System.out.println("                  All Time Usage:" + tempMeterRead.all_time_usage);
						System.out.println("                  Error Code 1:" + tempMeterRead.error_code_1);
						System.out.println("                  Error Code 2:" + tempMeterRead.error_code_2);
					}
				} catch (Exception e1) {
					System.out.println("FAILED TO GET ROW METER_READ DATA");
				}
			}
		} catch(Exception e) {
			System.out.println("FAILED TO GET METER DATA");
		}
	}
}