package devices.DHT;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import anywheresoftware.b4a.BA;
import jGPIO.jGPIO;


@BA.ShortName("SensorDHT")
@BA.Events(values= {
		"log(msg as string)",
		"measurement(value as DHT_Data)"
})
public class SensorDHT {

	private BA bax;
	private Object caller;
	private String event;
	private Object Me = this;
	
	private boolean inited = false;
	private boolean need_log_event = false;
	private boolean need_measurement_event = false;
	
	private File sensorpath;
	private File humiditypath;
	private File temperaturepath;
	
	public SensorDHT() {
		if (jGPIO.osname=="") jGPIO.detectOS();
	}
	
	/**
	 * Initialize DHT Sensor
	 * @param callerobject : callback object
	 * @param eventname : eventname
	 * @param pinnumber : pin number
	 */
	public void Initialize(BA ba, Object callerobject, String eventname, int pinnumber) {
		this.bax = ba;
		this.caller = callerobject;
		this.event = eventname;
		inited = false;
		if (bax instanceof BA) {
			if (caller!=null) {
				if (!event.isEmpty()) {
					if (bax.subExists(event+"_log")) {
						need_log_event = true;
						
					} 
					if (bax.subExists(event+"_measurement")) {
						need_measurement_event = true;
						
					} 
				} 
			} 
		} 
		
		
		if (!jGPIO.IsLinux) {
			raise_log("System is not Linux, SensorDHT can't be used");
			return;
		}
		
		String path = "/sys/devices/platform/dht11@"+pinnumber+"/iio:device0";
		sensorpath = new File(path);
		if (sensorpath.exists()) {
			humiditypath = new File(path,"in_humidityrelative_input");
			temperaturepath = new File(path, "in_temp_input");
			if (humiditypath.exists()) {
				if (temperaturepath.exists()) {
					inited = true;
				}
			}
		
			if (!inited) {
				if (!humiditypath.exists()) raise_log("Humidity Path is invalid");
				if (!temperaturepath.exists()) raise_log("Temperature Path is invalid");
			}
		} else {
			raise_log("DHT Sensor not found, put dtoverlay=dht11,gpiopin=pinnumber at /boot/config.txt");
		}
	}
		
	/**
	 * check if Already Initialized
	 * @return true if initialized
	 */
	public boolean IsInitialized() {
		return inited;
	}
	
	/**
	 * Measure Temperature and Humidity
	 * Will raise event measurement(value as DHT_Data)
	 * Between Read, must interval at least 2 seconds
	 * @return true if measurement success
	 */
	public boolean Read_Measurement() {
		if (inited) {
			try {
				double tt = Read_DHT_Value(temperaturepath);
				double hh = Read_DHT_Value(humiditypath);
				DHT_Data result = new DHT_Data(tt, hh);
				raise_measurement(result);
				return result.getIsValidMeasurement();
			} catch (Exception e) {
				raise_log("Failed Measurement, Exception="+e.getMessage());
			}
			
		}
		return false;
	}
	
	/**
	 * Read DHT Sensor
	 * 
	 * @param path : path of sensor
	 * @return -1 if failed
	 * @throws IOException
	 */
	private double Read_DHT_Value(File path)  {
		double result = -1;
		if (path != null) {
			if (path.exists()) {
				if (path.canRead()) {
					String stringresult;
					BufferedReader reader;
					try {
						reader = new BufferedReader(new FileReader(path.getAbsolutePath()));
						stringresult = reader.readLine();
						reader.close();
						if (stringresult!=null) {
							if (!stringresult.isEmpty()) {
								result = Double.valueOf(stringresult)/1000.0;
							}
						}
					} catch (Exception e1) {
						raise_log("Read_DHT_Value exception, Msg : "+e1.getMessage());
					}  
				}
			}
		}
		return result;
	}
	
	/**
	 * Read current Temperature
	 * Between Read , must interval at least 2 seconds
	 * @return -1 if failed
	 */
	public double Read_Temperature() {
		if (inited) {
			try {
				double tt = Read_DHT_Value(temperaturepath);
				return tt;
			} catch (Exception e) {
				
			} 
			
		}
		return -1;
	}
	
	/**
	 * Read current Humidity
	 * Between Read, must interval at least 2 seconds
	 * @return -1 if failed
	 */
	public double Read_Humidity() {
		if (inited) {
			try {
				double hh = Read_DHT_Value(humiditypath);
				return hh;
			} catch (Exception e) {
				
			} 
		}
		return -1;
	}
	

	private void raise_log(String msg) {
		if (need_log_event) {
			bax.raiseEventFromDifferentThread(Me, null, 0, event+"_log", false, new Object[] {msg});
		}
	}
	
	private void raise_measurement(DHT_Data value) {
		if (need_measurement_event) {
			
			bax.raiseEventFromDifferentThread(Me, null, 0, event+"_measurement", false, new Object[] {value});
			
		}
	}
}
