content: package net.azib.ipscan.util;
  
  import net.azib.ipscan.config.Version;
  import org.eclipse.swt.SWTError;
  import org.eclipse.swt.SWTException;
  
  import java.net.HttpURLConnection;
  import java.net.URL;
  import java.net.URLEncoder;
  import java.util.logging.Logger;
  
  import static java.nio.charset.StandardCharsets.UTF_8;
  import static java.util.logging.Level.FINE;
  import static net.azib.ipscan.config.Config.getConfig;
  
  /**
   * Utility class to send statistics to Google Analytics (GA4).
   * https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events?client_type=firebase
   */
  public class GoogleAnalytics {
  	public void report(String screen) {
  		report("page_view", screen);
  	}
  
  	public void report(String type, String content) {
  		try {
  			var config = getConfig();
  			if (!config.allowReports) return;
  			var url = new URL("https://www.google-analytics.com/mp/collect?measurement_id=" + Version.GA_ID + "&api_secret=" + Version.GA_SECRET);
  			var conn = (HttpURLConnection) url.openConnection();
  			conn.setRequestMethod("POST");
  			conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
  			conn.setRequestProperty("User-Agent", "Mozilla/5.0 (ipscan/" + Version.getVersion() + " " + System.getProperty("os.name") + " " + System.getProperty("os.version") + "; Java " + System.getProperty("java.version") + ")");
  			conn.setDoOutput(true);
  
  			var payload = new StringBuilder();
  			payload.append("{");
  			payload.append("\"client_id\":\"").append(config.getGaClientId()).append("\",");
  			payload.append("\"non_personalized_ads\":true,");
  			payload.append("\"events\":[{");
  			payload.append("\"name\":\"").append(type).append("\",");
  			payload.append("\"params\":{");
  			payload.append("\"app_version\":\"").append(Version.getVersion()).append("\",");
  			payload.append("\"app_name\":\"ipscan\",");
  			payload.append("\"language\":\"").append(config.getLocale()).append("\",");
  			payload.append("\"screen_resolution\":\"").append(config.forGUI().mainWindowSize[0]).append("x").append(config.forGUI().mainWindowSize[1]).append("\",");
  			payload.append("\"os_info\":\"").append(System.getProperty("os.name")).append(" ").append(System.getProperty("os.version")).append(" ").append(System.getProperty("os.arch")).append("\",");
  			payload.append("\"java_info\":\"").append("Java ").append(System.getProperty("java.version")).append("\"");
  
  			content = content.replace("\"", "\\\"");
  			if ("exception".equals(type)) {
  				payload.append(",\"exception_description\":\"").append(content).append("\"");
  			} else {
  				payload.append(",\"page_title\":\"").append(content).append("\"");
  				payload.append(",\"page_location\":\"").append("https://angryip.org/app/").append(URLEncoder.encode(content, UTF_8)).append("\"");
  			}
  
  			payload.append("}}]");
  			payload.append("}");
  
  			try (var os = conn.getOutputStream()) {
  				os.write(payload.toString().getBytes(UTF_8));
  			}
  
  			try (var is = conn.getInputStream()) {
  				is.readAllBytes();
  			}
  
  			conn.disconnect();
  		}
  		catch (Exception e) {
  			Logger.getLogger(getClass().getName()).log(FINE, "Failed to report", e);
  		}
  	}
  
  	public void report(Throwable e) {
  		report("exception", extractFirstStackFrame(e));
  	}
  
  	public void report(String message, Throwable e) {
  		report("exception", message + "\n" + extractFirstStackFrame(e));
  	}
  
  	static String extractFirstStackFrame(Throwable e) {
  		if (e == null) return "";
  		var stackTrace = e.getStackTrace();
  		StackTraceElement element = null;
  		for (var stackTraceElement : stackTrace) {
  			element = stackTraceElement;
  			if (element.getClassName().startsWith("net.azib.ipscan")) break;
  		}
  		var code = e instanceof SWTError ? ((SWTError) e).code : e instanceof SWTException ? ((SWTException) e).code : -1;
  		return e + (code >= 0 ? " (" + code + ")" : "") + (element == null ? "" : "\n" +
  			   element.getClassName() + "." + element.getMethodName() + ":" + element.getLineNumber()) +
  			   (e.getCause() != null ? ";\n" + extractFirstStackFrame(e.getCause()) : "");
  	}
  
  	public void asyncReport(final String screen) {
  		new Thread(() -> report(screen)).start();
  	}
  
  	public static void main(String[] args) {
  		new GoogleAnalytics().report("hello");
  	}
  }
  