package com.etherios.gae.connector.tank;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;

import javax.servlet.ServletException;
import javax.servlet.http.*;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import com.digi.connector.client.CloudConnection;
import com.digi.connector.client.models.DataPoint;
import com.etherios.gae.connector.tank.datastore.UserData;
import com.etherios.gae.connector.tank.models.TempLevelMeasure;
import com.etherios.gae.connector.tank.models.ValvesMeasure;
import com.google.gson.Gson;

@SuppressWarnings("serial")
public class TankStatusServlet extends BaseServlet {
	// Constants.
	private final static String VALVE_VAR_NAME = "valve";
	private final static String VALVE_VAL_NAME = "valveValue";
	private final static String VALVE_IN_VAR_NAME = "valveIN";
	private final static String VALVE_OUT_VAR_NAME = "valveOUT";
	private final static String LEVEL_VAR_NAME = "level";
	private final static String TEMPERATURE_VAR_NAME = "temperature";
	
	private final static String DEVICE_TARGET = "tank";
	
	private final static String DEVICE_INSTANCE = "tank";
	
	private final static int NUM_SAMPLES = 40;
	
	/*
	 * (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	public void doGet(HttpServletRequest req, HttpServletResponse resp) 
	throws ServletException, IOException {
		clearErrorMessage();

		UserData user = getUserFromSession(req);
		// Verify if the user is null (maybe the session expired), if so return an error.
		if (user == null) {
			String errorStatus = "({'error': '" + errorMessage + "', 'login':'true'})";
			resp.getWriter().write(errorStatus);
			return;
		}
		
		// Create the CloudConnection object with given user and password.
		CloudConnection cloudConnection = new CloudConnection(user.getUser(), user.getPassword(), user.getServer());
		
		// Get the selected device of the user.
		String selectedDevice = user.getSelectedDevice();
		String latitude = user.getLatitude();
		String longitude = user.getLongitude();
		if (latitude == null)
			latitude = "";
		if (longitude == null)
			longitude = "";
		
		HashMap<String, String> arguments = new HashMap<String, String>();
		arguments.put("order", "desc");
		
		// Get Temperature samples
		ArrayList<DataPoint> temperatureSamples = cloudConnection.getDataPoints("/" + selectedDevice + "/" + DEVICE_INSTANCE + "/" + TEMPERATURE_VAR_NAME, NUM_SAMPLES, arguments);
		if (temperatureSamples == null) {
			HashMap<String, String> errorResponse = new HashMap<String, String>();
			errorResponse.put("error", cloudConnection.getErrorMessage());
			
			Gson gson = new Gson();
			resp.getWriter().write(gson.toJson(errorResponse));
			return;
		}
		
		// Get Level samples
		ArrayList<DataPoint> levelSamples = cloudConnection.getDataPoints("/" + selectedDevice + "/" + DEVICE_INSTANCE + "/" + LEVEL_VAR_NAME, NUM_SAMPLES, arguments);
		if (levelSamples == null) {
			HashMap<String, String> errorResponse = new HashMap<String, String>();
			errorResponse.put("error", cloudConnection.getErrorMessage());
			
			Gson gson = new Gson();
			resp.getWriter().write(gson.toJson(errorResponse));
			return;
		}
		
		// Get Valve IN samples
		ArrayList<DataPoint> valveINSamples = cloudConnection.getDataPoints("/" + selectedDevice + "/" + DEVICE_INSTANCE + "/" + VALVE_IN_VAR_NAME, NUM_SAMPLES, arguments);
		if (valveINSamples == null) {
			HashMap<String, String> errorResponse = new HashMap<String, String>();
			errorResponse.put("error", cloudConnection.getErrorMessage());
			
			Gson gson = new Gson();
			resp.getWriter().write(gson.toJson(errorResponse));
			return;
		}
		
		// Get Valve OUT samples
		ArrayList<DataPoint> valveOUTSamples = cloudConnection.getDataPoints("/" + selectedDevice + "/" + DEVICE_INSTANCE + "/" + VALVE_OUT_VAR_NAME, NUM_SAMPLES, arguments);
		if (valveOUTSamples == null) {
			HashMap<String, String> errorResponse = new HashMap<String, String>();
			errorResponse.put("error", cloudConnection.getErrorMessage());
			
			Gson gson = new Gson();
			resp.getWriter().write(gson.toJson(errorResponse));
			return;
		}
		
		ArrayList<TempLevelMeasure> tempLevelMeasures = new ArrayList<TempLevelMeasure>();
		ArrayList<ValvesMeasure> valvesMeasures = new ArrayList<ValvesMeasure>();
		
		DateTimeFormatter formatter = DateTimeFormat.forPattern("MMMM dd, yyyy HH:mm:ss");
		DateTimeFormatter engFormatter = formatter.withLocale(Locale.ENGLISH);
		for (int i = 0; i < temperatureSamples.size(); i++) {
			DataPoint dataPoint = temperatureSamples.get(i);
			
			DateTime date = new DateTime(Long.parseLong(dataPoint.getTimestamp()));
			String dateFormatted = date.toString(engFormatter);
			
			tempLevelMeasures.add(new TempLevelMeasure(null, dataPoint.getData(), dateFormatted));
		}
		
		for (int i=0; i<levelSamples.size(); i++) {
			DataPoint dataPoint = levelSamples.get(i);
			
			DateTime date = new DateTime(Long.parseLong(dataPoint.getTimestamp()));
			String dateFormatted = date.toString(engFormatter);
			
			tempLevelMeasures.add(new TempLevelMeasure(dataPoint.getData(), null, dateFormatted));
		}
		
		for (int i=0; i<valveINSamples.size(); i++) {
			DataPoint dataPoint = valveINSamples.get(i);
			
			String value = dataPoint.getData();
			if (value.equals("0"))
				value = "1";
			else
				value = "0";
			
			DateTime date = new DateTime(Long.parseLong(dataPoint.getTimestamp()));
			String dateFormatted = date.toString(engFormatter);
			
			valvesMeasures.add(new ValvesMeasure(value, null, dateFormatted));
		}
		
		for (int i=0; i<valveOUTSamples.size(); i++) {
			DataPoint dataPoint = valveOUTSamples.get(i);
			
			String value = dataPoint.getData();
			if (value.equals("0"))
				value = "1";
			else
				value = "0";
			
			DateTime date = new DateTime(Long.parseLong(dataPoint.getTimestamp()));
			String dateFormatted = date.toString(engFormatter);
			
			valvesMeasures.add(new ValvesMeasure(null, value, dateFormatted));
		}
		
		Gson gson = new Gson();
		String tankStatus = "({'level': " + levelSamples.get(0).getData() + 
			", 'temperature': " + temperatureSamples.get(0).getData() + 
			", 'valveIN': '" + valveINSamples.get(0).getData() + 
			"', 'valveOUT': '" + valveOUTSamples.get(0).getData() + 
			"', 'tempLevelSamples': '" + gson.toJson(tempLevelMeasures) + 
			"', 'valvesSamples': '" + gson.toJson(valvesMeasures) + 
			"', 'latitude': '" + latitude + 
			"', 'longitude': '" + longitude +
			"'})";
		resp.getWriter().write(tankStatus);
	}
	
	/*
	 * (non-Javadoc)
	 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		UserData user = getUserFromSession(req);
		if (user == null) {
			resp.getWriter().write("({'status': 'error', 'text': '" + errorMessage + "', 'login': 'true'})");
			return;
		}
		
		// Read request parameters.
		String valveName = req.getParameter(VALVE_VAR_NAME);
		String valveVal = req.getParameter(VALVE_VAL_NAME);
		String deviceRequestPayload = generateDeviceRequestPayload(valveName, valveVal);
		
		// Create the CloudConnection object.
		CloudConnection connection = new CloudConnection(user.getUser(), user.getPassword(), user.getServer());
		String deviceRequestStatus = "";
		String response = connection.sendDeviceRequest(deviceRequestPayload, DEVICE_TARGET, user.getSelectedDevice());
		if (response == null)
			deviceRequestStatus = "({'status': 'error', 'text': '" + connection.getErrorMessage() + "'})";
		else {
			String valveStatus = response.substring(response.indexOf(">") + 1, response.lastIndexOf("<"));
			if (valveStatus.equals("True"))
				valveStatus = "0";
			else
				valveStatus = "1";
			deviceRequestStatus = "({'status': 'success', 'text': 'Command sent successfully.', '" + valveName + "': '" + valveStatus + "'})";
		}
		resp.getWriter().write(deviceRequestStatus);
		resp.getWriter().close();
	}
	
	/**
	 * Generates the payload of the device request to send.
	 * @return
	 */
	private String generateDeviceRequestPayload(String valveVarName, String valveValName) {
		String payload = valveVarName + "=" + valveValName;
		return payload;
	}
}
