package devices.ups.ica.sin2100c;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

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

@BA.ShortName("ICA_SIN2100C")
@BA.Events(values= {
		"log(msg as string)"
})

/**
 * UPS ICA SIN-2100C monitoring
 * @author rdkartono
 *
 * This class need networkupstool (nut)
 * to install :
 * sudo apt-get update && sudo apt-get upgrade
 * sudo apt-get install nut
 * 
 * edit on /etc/nut/ups.conf, to add configuration
 * [upsname]
 *     driver=blazer_usb
 *     port=auto
 *     desc="ICA SIN-2100C" 
 *     
 * edit on /etc/nut/nut.conf
 * MODE=standalone
 * 
 * reboot
 * 
 * try checking with upsc -l
 * should show upsname in result
 * 
 * try checking result with upsc upsname
 * should show values from ups
 * 
 * to start ups driver : sudo upsdrvctl start <nama ups>
 * to stop ups driver : sudo upsdrvctl stop <nama ups>
 * to shutdown driver : sudo upsdrvctl shutdown <nama ups>
 */
public class SIN2100C {
	private BA ba;
	private Object caller;
	private String event;
	private final Object Me = this;
	private boolean need_log_event = false;
	private boolean opened = false;
	private String upsname="";
	
	public SIN2100C() {
		if (jGPIO.osname.isEmpty()) jGPIO.detectOS();
	}
	
	/**
	 * Initialize SIN2100C Object
	 * @param callerobject : caller object
	 * @param eventname : eventname
	 */
	public void Initialize(BA bax, Object callerobject, String eventname) {
		opened = false;
		ba = bax;
		caller = callerobject;
		event = eventname.trim();
		if (ba instanceof BA) {
			if (caller != null) {
				if (!event.isEmpty()) {
					need_log_event = ba.subExists(event+"_log");
				}
			}
		}
		
	}
	
	/**
	 * Open UPS 
	 * @param upsname : ups name, as created in /etc/nut/ups.conf
	 * @return true if opened
	 */
	public boolean Open(String upsname) {
		opened = false;
		this.upsname = "";
		upsname = upsname.trim();
		if (!upsname.isEmpty()) {
			if (jGPIO.IsLinux) {
				File nut = new File("/etc/nut");
				if (nut.exists()) {
					if (nut.isDirectory()) {
						File nutconf = new File(nut, "nut.conf");
						if (nutconf.exists()) {
							if (nutconf.isFile()) {
								File upsconf = new File(nut, "ups.conf");
								if (upsconf.exists()) {
									if (upsconf.isFile()) {
										try {
											Process process = Runtime.getRuntime().exec("upsc -l");
											InputStream inp = process.getInputStream();
											if (inp != null) {
												BufferedReader buf = new BufferedReader(new InputStreamReader(inp));
												String rx;
												do {
													rx = buf.readLine();
													if (rx != null) {
														rx = rx.trim();
														if (rx.equalsIgnoreCase(upsname)) {
															this.upsname = upsname;
															opened = true;
														}
													}
												} while (rx != null);
											}
										} catch (Exception e) {
											raise_log("Unable to run upsc, Msg : "+e.getMessage());
										}
									} else {
										raise_log("ups.conf is not file");
									}
								} else {
									raise_log("ups.conf not available");
								}
							} else {
								raise_log("nut.conf is not file");
							}
						} else {
							raise_log("nut.conf not available");
						}
					} else {
						raise_log("Invalid NUT installation");
					}
				} else {
					raise_log("NUT not installed");
				}
			} else {
				raise_log("Only support Linux system");
			}
		} else {
			raise_log("UPS Name is empty string");
		}
		
		return opened;
	}
	
	/**
	 * Check if Opened succesfully
	 * @return true if opened
	 */
	public boolean IsOpened() {
		return opened;
	}
	
	/**
	 * Check opened ups name
	 * @return empty string if ups is not opened
	 */
	public String GetName() {
		return upsname;
	}
	
	/**
	 * Get UPS Status
	 * @return SIN2100C_Data object . Check IsValidData before using these data
	 */
	public SIN2100C_Data GetMeasurement() {
		if (opened) {
			if (!upsname.isEmpty()) {
				try {
					Process xx = Runtime.getRuntime().exec("upsc "+upsname);
					InputStream inp = xx.getInputStream();
					if (inp!=null) {
						return new SIN2100C_Data(inp);
					}
				} catch (IOException e) {
					raise_log("Error GetMeasurement, Msg : "+e.getMessage());
				}
				
			}
		}
		
		return new SIN2100C_Data();			// data asal, invalid
	}
	
	private List<String> printlog(InputStream inp) {
		
		if (inp instanceof InputStream) {
			BufferedReader buf = new BufferedReader(new InputStreamReader(inp));
			List<String> result = new ArrayList<String>();
			while(true) {
				String rx;
				try {
					rx = buf.readLine();
					if (rx instanceof String) {
						if (!rx.isEmpty()) {
							result.add(rx);
							BA.Log(rx);
						}
					} else break;
				} catch (IOException e) {
					break;
				}
				
			}
			return result;
		}
		return null;
	}
	
	/**
	 * Send command upsdrvctl start <upsname>
	 * @return true if success
	 */
	public boolean Start_UPS_Driver() {
		if (opened) {
			if (!upsname.isEmpty()) {
				try {
					Process xx = Runtime.getRuntime().exec("upsdrvctl start "+upsname);
					InputStream inp = xx.getInputStream();
					if (inp != null) {
						printlog(inp);
						
						return true;
					}
				} catch(IOException e) {
					raise_log("Error Start_UPS_Driver, Msg : "+e.getMessage());
				}
			}
		}
		return false;
	}
	
	/**
	 * Send command upsdrvctl stop <upsname>
	 * @return true if success
	 */
	public boolean Stop_UPS_Driver() {
		if (opened) {
			if (!upsname.isEmpty()) {
				try {
					Process xx = Runtime.getRuntime().exec("upsdrvctl stop "+upsname);
					InputStream inp = xx.getInputStream();
					if (inp != null) {
						printlog(inp);
						return true;
					}
				} catch(IOException e) {
					raise_log("Error Stop_UPS_Driver, Msg : "+e.getMessage());
				}
			}
		}
		return false;
	}
	
	/**
	 * Send command upsdrvctl shutdown <upsname>
	 * @return true if success
	 */
	public boolean Shutdown_UPS() {
		if (opened) {
			if (!upsname.isEmpty()) {
				try {
					Process xx = Runtime.getRuntime().exec("upsdrvctl shutdown "+upsname);
					InputStream inp = xx.getInputStream();
					if (inp != null) {
						printlog(inp);
						return true;
					}
				} catch(IOException e) {
					raise_log("Error Shutdown_UPS_Driver, Msg : "+e.getMessage());
				}
			}
		}
		return false;
	}

	private void raise_log(String msg) {
		if (need_log_event) {
			ba.raiseEventFromDifferentThread(Me, null, 0, event+"_log", false, new Object[] {msg});
		}
	}
}
