package MeterBenchmark;

import java.util.concurrent.Semaphore;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;

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

import java.util.Calendar;
import java.util.Date;

import com.toshiba.mwcloud.gs.RowKey;

class Meter {
	@RowKey
	public long id;
	
	public String contact_name;
	public String email;
	public String phone_number;
	public String description;
	public String address;
	public String city;
	public String state_province;
	public Date last_reading;
	public float latitude;
	public float longitude;
}
class MeterRead {
	@RowKey
	public Date timestamp;
	
	public double usage_since_read;
	public double usage_this_hour;
	public double usage_this_day;
	public double usage_this_week;
	public double usage_this_month;
	public double usage_this_year;
	public double all_time_usage;
	public long error_code_1;
	public long error_code_2;
}

class GridDBClient extends Client {

	Properties sourceProps = new Properties();
	GridStore store;
	//
	private String meterContainerName = "METERS";
	private String meterReadsContainerName = "METER_READS";
	//
	private Collection<String,Meter> metersCol;
	TimeSeries<MeterRead> meterData ; 
	//private Query<Meter> meterQuery;
	//private RowSet<Meter> meterRows;
	//
	Meter meter;
	MeterRead meterRead;
	//
	static Semaphore mutex = new Semaphore(1);
	
	public GridDBClient () {
		InputStream input;
		boolean debug = true;
		boolean worked = false;
		try {
			input = new FileInputStream("gridstore.properties");
			sourceProps.load(input);
		} catch (Exception e) {
			System.out.println("COULD NOT LOAD gridstore.properties");
			System.exit(1);
		}
		try {
			store = GridStoreFactory.getInstance().getGridStore(sourceProps);
			this.metersCol = store.putCollection(meterContainerName, Meter.class);
			
		} catch (GSException e) {
			System.out.println("Could not connect to GridDB");
			e.printStackTrace();
			System.exit(1);
			
		}
		
	}
	public double getUsage(int id, Date start, Date end) {
		float result = 0;
		Calendar startcal = Calendar.getInstance();
		Calendar endcal = Calendar.getInstance();
		startcal.setTime(start);
		endcal.setTime(end);
		String endMonthF = TimestampUtils.format(endcal.getTime());
		String startMonthF = TimestampUtils.format(startcal.getTime());
		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 + "\')";
		try {
			TimeSeries<MeterRead> tempSeries = store.getTimeSeries(meterReadsContainerName + "_" + 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) {
			return 0;
		}
	}
	public float monthlyUsage(long id, int year, int month) {
		int month1 = month + 5;
		int year1 = year + 1842;
		float result = 0;
		//
		Calendar calstart = Calendar.getInstance();
		Calendar calend = Calendar.getInstance();
		calstart.set(Calendar.YEAR, year1);
		calend.set(Calendar.YEAR, year1);
		calstart.set(Calendar.MONTH, month1);
		calend.set(Calendar.MONTH, month1);
		calstart.set(Calendar.DAY_OF_MONTH, 1);
		calend.add(Calendar.MONTH, 1);
		calend.set(Calendar.DAY_OF_MONTH, 0);
		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);
		String endMonthF = TimestampUtils.format(calend.getTime());
		String startMonthF = TimestampUtils.format(calstart.getTime());
		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 + "\')";
		try {
			TimeSeries<MeterRead> tempSeries = store.getTimeSeries(meterReadsContainerName + "_" + 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) {
			return 0;
		}
	}

	@Override
	public void writeUsage(Date timestamp, double usage_since_read, double usage_this_hour, double usage_this_day, double usage_this_week, double usage_this_month, double usage_this_year, double all_time_usage, int meter_id) {
		MeterRead mr = new MeterRead();
		mr.timestamp = timestamp;
		mr.usage_since_read = usage_since_read;
		mr.usage_this_hour = usage_this_hour;
		mr.usage_this_day = usage_this_day;
		mr.usage_this_week = usage_this_week;
		mr.usage_this_month = usage_this_month;
		mr.usage_this_year = usage_this_year;
		mr.all_time_usage = all_time_usage;
		Meter m = new Meter();
		m.id = meter_id;
		m.last_reading = timestamp;
		// Made up data
		m.address = "123 street";
		m.city = "fakecity";
		m.contact_name = "John Smith";
		m.description = "Some description";
		m.email = "fakeEmail@fake.com";
		m.latitude = (float) 1.253;
		m.longitude = (float) 5.234;
		m.phone_number = "1-123-456-7890";
		m.state_province = "CA";
		mr.error_code_1 = 12345;
		mr.error_code_2 = 67890;
		//
		//
		try {
			if (meterData == null) {
				meterData = store.putTimeSeries(meterReadsContainerName + "_" + meter_id, MeterRead.class);
			} 
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);

		}	
		try {
			metersCol.setAutoCommit(false);
			metersCol.put(m);
			metersCol.commit();
			meterData.setAutoCommit(false);
			meterData.put(mr.timestamp, mr);
			meterData.commit();
		} catch (GSException e) {
			e.printStackTrace();
		}
	}

	public void write() {
		// currently using updateUsage
		/*
		//System.out.println("GridDB Write");
		try {
			TimeSeries<MeterRead> meterData = null;
			meterData = store.putTimeSeries(meterReadsContainerName + "_" + meter.id, MeterRead.class);
			meterData.setAutoCommit(false);
			//metersCol.put(meter);
			//metersCol.commit();
			meterData.put(meterRead.timestamp, meterRead);
			meterData.commit();
		} catch (GSException e) {
			System.out.println("Could not write to Database");
			e.printStackTrace();
		}
		System.out.println("Wrote to DB");
		*/
	}
	
	@Override
	public void finalize() {
		try {
			store.close();
		} catch (GSException e) {
			System.out.println("Could not close server");
			e.printStackTrace();
		}
	}
}
