package syslog;

import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.keywords.Regex;
import anywheresoftware.b4a.keywords.Regex.MatcherWrapper;

@BA.ShortName("DWM312_Syslog_Consumer")
@BA.Events(values= {
		"log(msg as string)",
		"internetconnection(connected as boolean)",
		"updatednetworkinfo",
		"gsmtime(value as long)",
		"changenetwork(previous as IMSI_Data, current as IMSI_Data)"
})
public class DWM312_Syslog_Consumer implements SyslogEvent {

	private BA ba;
	private Object caller;
	private String event;
	private final Object Me = this;
	private boolean need_log_event = false;
	private boolean need_internetconnection_event = false;
	private boolean need_updatednetworkinfo_event = false;
	private boolean need_gsmtime_event = false;
	private boolean need_changenetwork_event = false;
	
	private String _identifier = "DWM-312";
	private String _ipaddress = "";
	private String _dns = "";
	private String _sec_dns = "";
	private String _hostaddress = "";
	private String _gwaddress = "";
	private String _ifname = "";
	private String _wantype = "";
	private String _mode = "";
	private String _currentSIM = "";
	private String _wanID = "";
	private IMSI_Data _currentIMSI = new IMSI_Data("");
	
	private final String regex_ipaddress = "^<14>MultiWANChk2:\\s*printnode\\[\\d+\\]:\\s*(ipaddr)\\s*(->)\\s*(\\d+.\\d+.\\d+.\\d+)\\s*$";
	private final String regex_dns = "^<14>MultiWANChk2:\\s*printnode\\[\\d+\\]:\\s*(dns)\\s*(->)\\s*(\\d+.\\d+.\\d+.\\d+)\\s*$";
	private final String regex_sec_dns = "^<14>MultiWANChk2:\\s*printnode\\[\\d+\\]:\\s*(sec dns)\\s*(->)\\s*(\\d+.\\d+.\\d+.\\d+)\\s*$";
	private final String regex_hostaddress = "^<14>MultiWANChk2:\\s*printnode\\[\\d+\\]:\\s*(hostaddr)\\s*(->)\\s*(\\d+.\\d+.\\d+.\\d+)\\s*$";
	private final String regex_gwaddress = "^<14>MultiWANChk2:\\s*printnode\\[\\d+\\]:\\s*(gwaddr)\\s*(->)\\s*(\\d+.\\d+.\\d+.\\d+)\\s*$";
	private final String regex_ifname = "^<14>MultiWANChk2:\\s*printnode\\[\\d+\\]:\\s*(ifname)\\s*(->)\\s*(\\d+.\\d+.\\d+.\\d+)\\s*$";
	private final String regex_wantype = "^<14>MultiWANChk2:\\s*printnode\\[\\d+\\]:\\s*(wantype)\\s*(->)\\s*(\\d+.\\d+.\\d+.\\d+)\\s*$";
	private final String regex_mode = "^<14>MultiWANChk2:\\s*printnode\\[\\d+\\]:\\s*(mode)\\s*(->)\\s*(\\d+.\\d+.\\d+.\\d+)\\s*$";
	
	private final String regex_connected = "^<14>commander: WAN (\\d+) connected\\s+$";
	private final String regex_disconnected = "^<14>commander: WAN (\\d+) disconnected\\s+$";
	private final String regex_SIM_ACTIVE = "^<14>O3G\\/dualsim_switch: Start dualsim for \\[(\\w+)\\]!!\\s+$";
	private final String regex_SIM_Time = "^<135>udhcpd\\[\\d+\\d]: oldsystemtime=\\d+ newsystemtime=(\\d+)\\s*$";
	private final String regex_IMSI="^<14>O3G\\/mal_daemon_0: previous IMSI\\[\\d*\\], current IMSI\\[(\\d*)\\], change record..\\s*$";
	
	public void Initialize(BA bax, Object callerobject, String eventname) {
		ba = bax;
		caller = callerobject;
		event = eventname.trim();
		if (ba instanceof BA) {
			if (caller != null) {
				if (!event.isEmpty()) {
					need_log_event = ba.subExists(event+"_log");
					need_internetconnection_event=  ba.subExists(event+"_internetconnection");
					need_updatednetworkinfo_event = ba.subExists(event+"_updatednetworkinfo");
					need_gsmtime_event = ba.subExists(event+"_gsmtime");
					need_changenetwork_event = ba.subExists(event+"_changenetwork");
				}
			}
		}
	}
	
	// event dari SyslogServer
	@BA.Hide
	@Override
	public void newdata(String fromip, int fromport, byte[] data) {
		String cmd = new String(data).trim();
		if (cmd.isEmpty()) return;
		
		//TODO : nanti hapus ini 
		raise_log(cmd);
		
		// info SIM mana yang aktif
		//<14>O3G/dualsim_switch: dualsim_switch main:index_3G=0, start[3G1] 
		//<14>O3G/dualsim_switch: Start dualsim for [3G1]!! 
		
		// buat info jaringan
		//<14>MultiWANChk2: printnode[109]: index       -> 13 
		//<14>MultiWANChk2: printnode[110]: mode        -> 0 
		//<14>MultiWANChk2: printnode[111]: wantype     -> 16 
		//<14>MultiWANChk2: printnode[112]: ifname      -> usbnet0 
		//<14>MultiWANChk2: printnode[113]: gwaddr      -> 0.0.0.0 
		//<14>MultiWANChk2: printnode[114]: ipaddr      -> 10.53.41.49 
		//<14>MultiWANChk2: printnode[115]: dns         -> 112.215.198.254 
		//<14>MultiWANChk2: printnode[116]: sec dns     -> 112.215.71.243 
		//<14>MultiWANChk2: printnode[117]: hostaddr    -> 112.215.198.254 
		//<14>MultiWANChk2: printnode[118]: sec_hostaddr->  
		//<14>MultiWANChk2: printnode[119]: interval    -> 3 
		
		// info WAN connected / disconnected
		//<14>commander: WAN 14 connected  
		//<14>commander: WAN 14 disconnected  
		
		// info jam GSM
		//<135>udhcpd[1841]: oldsystemtime=1356998471 newsystemtime=1598858696
		
		// info jaringan 
		//<14>O3G/mal_daemon_0: previous IMSI[], current IMSI[510113840731039], change record.. 
		
		if (Regex.IsMatch(regex_dns, cmd)) {
			String result = Regex.Matcher(regex_dns, cmd).Group(3).trim();		// grup mulai dari 1, value di grup 3
			if (!_dns.equalsIgnoreCase(result)) {
				// ada perubahan data
				_dns = result;
				raise_log("New DNS : "+_dns);
				if (complete_network_info()) raise_updatednetworkinfo();
			}
			return;
		}
		
		if (Regex.IsMatch(regex_sec_dns, cmd)) {
			String result = Regex.Matcher(regex_sec_dns, cmd).Group(3).trim();		// grup mulai dari 1, value di grup 3
			if (!_sec_dns.equalsIgnoreCase(result)) {
				// ada perubahan data
				_sec_dns = result;
				raise_log("New Secondary_DNS : "+ _sec_dns);
				if (complete_network_info()) raise_updatednetworkinfo();
			}
		}
		
		if (Regex.IsMatch(regex_gwaddress, cmd)) {
			String result = Regex.Matcher(regex_gwaddress, cmd).Group(3).trim();		// grup mulai dari 1, value di grup 3
			if (!_gwaddress.equalsIgnoreCase(result)) {
				// ada perubahan data
				_gwaddress = result;
				raise_log("New Gateway_Address : "+ _gwaddress);
				if (complete_network_info()) raise_updatednetworkinfo();
			}
			return;
		}
		
		if (Regex.IsMatch(regex_hostaddress, cmd)) {
			String result = Regex.Matcher(regex_hostaddress, cmd).Group(3).trim();		// grup mulai dari 1, value di grup 3
			if (!_hostaddress.equalsIgnoreCase(result)) {
				// ada perubahan data
				_hostaddress = result;
				raise_log("New Host_Address : "+ _hostaddress);
				if (complete_network_info()) raise_updatednetworkinfo();
			}
			return;
		}
		if (Regex.IsMatch(regex_ifname, cmd)) {
			String result = Regex.Matcher(regex_ifname, cmd).Group(3).trim();		// grup mulai dari 1, value di grup 3
			if (!_ifname.equalsIgnoreCase(result)) {
				// ada perubahan data
				_ifname = result;
				raise_log("New Interface_Name : "+ _ifname);
				if (complete_network_info()) raise_updatednetworkinfo();
			}
			return;
		}
		if (Regex.IsMatch(regex_ipaddress, cmd)) {
			String result = Regex.Matcher(regex_ipaddress, cmd).Group(3).trim();		// grup mulai dari 1, value di grup 3
			if (!_ipaddress.equalsIgnoreCase(result)) {
				// ada perubahan data
				_ipaddress = result;
				raise_log("New IP_Address : "+ _ipaddress);
				if (complete_network_info()) raise_updatednetworkinfo();
			}
			return;
		}
		if (Regex.IsMatch(regex_mode, cmd)) {
			String result = Regex.Matcher(regex_mode, cmd).Group(3).trim();		// grup mulai dari 1, value di grup 3
			if (!_mode.equalsIgnoreCase(result)) {
				// ada perubahan data
				_mode = result;
				raise_log("New Mode : "+ _mode);
				if (complete_network_info()) raise_updatednetworkinfo();
			}
			return;
		}
		if (Regex.IsMatch(regex_wantype, cmd)) {
			String result = Regex.Matcher(regex_wantype, cmd).Group(3).trim();		// grup mulai dari 1, value di grup 3
			if (!_wantype.equalsIgnoreCase(result)) {
				// ada perubahan data
				_wantype = result;
				raise_log("New WAN_Type : "+ _wantype);
				if (complete_network_info()) raise_updatednetworkinfo();
			}
			return;
		}
		
		if (Regex.IsMatch(regex_SIM_ACTIVE, cmd)) {
			String result = Regex.Matcher(regex_SIM_ACTIVE, cmd).Group(1).trim();	// grup mulai dari 1, value di grup 1
			if (! _currentSIM.equalsIgnoreCase(result)) {
				// ada perubahan data
				_currentSIM = result;
				raise_log("Selected SIM : "+_currentSIM);
			}
			return;
		}
		
		if (Regex.IsMatch(regex_connected, cmd)) {
			String result = Regex.Matcher(regex_connected, cmd).Group(1).trim();		// grup mulai dari 1, value di grup 1
			if (! _wanID.equalsIgnoreCase(result)) {
				// ada perubahan data
				_wanID = result;
				raise_log("New WAN ID : "+_wanID);
			}
			raise_internetconnection(true);
			return;
		}
		
		if (Regex.IsMatch(regex_disconnected, cmd)) {
			_wanID = "";
			raise_log("WAN ID cleared");
			
			// clear all network info
			_dns = "";
			_gwaddress = "";
			_hostaddress = "";
			_ifname = "";
			_ipaddress = "";
			_mode = "";
			_sec_dns = "";
			_wantype = "";
			
			raise_internetconnection(false);
			return;
		}
		
		if (Regex.IsMatch(regex_SIM_Time, cmd)) {
			String result = Regex.Matcher(regex_SIM_Time, cmd).Group(1).trim();
			try {
				long value = Long.parseLong(result);
				raise_gsmtime(value);
			} catch(NumberFormatException e) {
				// do nothing
				raise_log("Error Long Parsing System Time = "+result+", Msg : "+e.getMessage());
			}
			return;
		}
		
		if (Regex.IsMatch(regex_IMSI, cmd)) {
			MatcherWrapper rex = Regex.Matcher(regex_IMSI, cmd);
			if (rex instanceof MatcherWrapper) {
				IMSI_Data prev = new IMSI_Data(rex.Group(1));
				IMSI_Data current = new IMSI_Data(rex.Group(2));
				_currentIMSI = current;
				raise_changenetwork(prev, current);
			}
		}
		
	}
	
	private boolean complete_network_info() {
		if (_dns.isEmpty()) return false;
		if (_gwaddress.isEmpty()) return false;
		if (_hostaddress.isEmpty()) return false;
		if (_ifname.isEmpty()) return false;
		if (_ipaddress.isEmpty()) return false;
		if (_mode.isEmpty()) return false;
		if (_sec_dns.isEmpty()) return false;
		if (_wantype.isEmpty()) return false;
		return true;
	}
	
	/**
	 * Get Current IMSI Data in use
	 * @return IMSI_Data
	 */
	public IMSI_Data getCurrentIMSI() {
		return _currentIMSI;
	}
	
	/***
	 * Get WAN ID
	 * @return empty string if not connected
	 */
	public String getWAN_ID() {
		return _wanID;
	}
	
	/**
	 * Detected Public IP Address
	 * @return empty string if disconnected
	 */
	public String getIPAddress() {
		return _ipaddress;
	}
	
	/**
	 * Detected DNS Address
	 * @return empty string if disconnected
	 */
	public String getDNS() {
		return _dns;
	}
	
	/**
	 * Detected Secondary DNS Address
	 * @return empty string if disconnected
	 */
	public String getSecondaryDNS() {
		return _sec_dns;
	}
	
	/**
	 * Detected Gateway Address
	 * @return empty string if disconnected
	 */
	public String getGateway() {
		return _gwaddress;
	}
	
	/**
	 * Detected Host Address
	 * @return empty string if disconnected
	 */
	public String getHostAddress() {
		return _hostaddress;
	}
	
	/**
	 * Detected Interface Name
	 * @return empty string if disconnected
	 */
	public String getInterfaceName() {
		return _ifname;
	}
	
	/**
	 * Detected Mode
	 * @return empty string if disconnected
	 */
	public String getMode() {
		return _mode;
	}
	
	/**
	 * Detected WAN Type
	 * @return empty string if disconnected
	 */
	public String getWANType() {
		return _wantype;
	}
	
	/**
	 * Current SIM slot being used
	 * @return empty string if nothing selected
	 */
	public String getCurrentSIM() {
		return _currentSIM;
	}
	
	/**
	 * Get / Set Syslog Consumer identification
	 */
	public String getIdentifier() {
		return _identifier;
	}
	
	public void setIdentifier(String value) {
		if (value instanceof String) {
			value = value.trim();
			if (!value.isEmpty()) {
				_identifier = value.trim();
			}
		}
	}
	
	private void raise_log(String value) {
		if (need_log_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_log", false, new Object[] {value});
	}

	private void raise_internetconnection(boolean value) {
		if (need_internetconnection_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_internetconnection", false, new Object[] {value});
	}
	
	private void raise_updatednetworkinfo() {
		if (need_updatednetworkinfo_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_updatednetworkinfo", false, null);
	}
	
	private void raise_gsmtime(long value) {
		if (need_gsmtime_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_gsmtime", false, new Object[] {value});
	}
	
	private void raise_changenetwork(IMSI_Data prev, IMSI_Data current) {
		if (need_changenetwork_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_changenetwork", false, new Object[] {prev, current});
	}
}
