<commit_before>package ui;

import java.awt.Rectangle;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.egit.github.core.IRepositoryIdProvider;
import org.eclipse.egit.github.core.RepositoryId;

import service.ServiceManager;
import storage.DataManager;
import ui.components.HTStatusBar;
import ui.issuecolumn.ColumnControl;
import util.DialogMessage;
import util.PlatformEx;
import util.PlatformSpecific;
import util.Utility;
import util.events.BoardSavedEvent;
import util.events.Event;
import util.events.EventDispatcher;
import util.events.EventHandler;
import util.events.LoginEvent;
import browserview.BrowserComponent;

import com.google.common.eventbus.EventBus;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HWND;

public class UI extends Application implements EventDispatcher {

	private static final int VERSION_MAJOR = 2;
	private static final int VERSION_MINOR = 0;
	private static final int VERSION_PATCH = 1;

	public static final String ARG_UPDATED_TO = "--updated-to";

	private static final double WINDOW_DEFAULT_PROPORTION = 0.6;

	private static final Logger logger = LogManager.getLogger(UI.class.getName());
	private static HWND mainWindowHandle;

	// Main UI elements

	private Stage mainStage;
	private ColumnControl columns;
	private MenuControl menuBar;
	private BrowserComponent browserComponent;
	private RepositorySelector repoSelector;
	
	// Bview changes
	private String currentPageSource = "";

	// Events

	private EventBus events;

	// Application arguments

	private HashMap<String, String> commandLineArgs;

	public static void main(String[] args) {
		Application.launch(args);
	}

	private static UI instance;
	public static UI getInstance() {
		return instance;
	}

	@Override
	public void start(Stage stage) throws IOException {

		instance = this;

		//log all uncaught exceptions
		Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> {
            logger.error(throwable.getMessage(), throwable);
        });

		events = new EventBus();

		repoSelector = createRepoSelector();

		browserComponent = new BrowserComponent(this);
		initCSS();
		mainStage = stage;
		stage.setMaximized(false);
		Scene scene = new Scene(createRoot());
		setupMainStage(scene);
		loadFonts();
		applyCSS(scene);
		getUserCredentials();
		commandLineArgs = initialiseCommandLineArguments();

		DataManager.getInstance();
	}

	private void getUserCredentials() {
		repoSelector.setDisable(true);
		new LoginDialog(mainStage, columns).show().thenApply(success -> {
			if (success) {
				browserComponent.initialise();
				setExpandedWidth(false);
				columns.loadIssues();
				triggerEvent(new LoginEvent());
				repoSelector.setDisable(false);
				repoSelector.refreshComboBoxContents();
				repoSelector.setValue(ServiceManager.getInstance().getRepoId().generateId());
				triggerEvent(new BoardSavedEvent());
			} else {
				quit();
			}
			return true;
		}).exceptionally(e -> {
			logger.error(e.getLocalizedMessage(), e);
			return false;
		});
	}

	private static String CSS = "";

	public void initCSS() {
		CSS = this.getClass().getResource("hubturbo.css").toString();
	}

	public static void applyCSS(Scene scene) {
		scene.getStylesheets().clear();
		scene.getStylesheets().add(CSS);
	}

	public static void loadFonts(){
		Font.loadFont(UI.class.getResource("/resources/octicons/octicons-local.ttf").toExternalForm(), 32);
	}

	private void setupMainStage(Scene scene) {
		mainStage.setTitle("HubTurbo " + Utility.version(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH));
		mainStage.setScene(scene);
		mainStage.show();
		mainStage.setOnCloseRequest(e -> quit());
		initialiseJNA();
		mainStage.focusedProperty().addListener(new ChangeListener<Boolean>() {
			@Override
			public void changed(ObservableValue<? extends Boolean> unused, Boolean wasFocused, Boolean isFocused) {
				if (!isFocused) {
					return;
				}
				if (PlatformSpecific.isOnWindows()) {
					browserComponent.focus(mainWindowHandle);
				}
				PlatformEx.runLaterDelayed(() -> {
					// A refresh is triggered if:
					// 1. Repo-switching is not disabled (meaning an update is not in progress)
					// 2. The repo-switching box is not in focus (clicks on it won't trigger this)
					boolean shouldRefresh = isRepoSwitchingAllowed() && !repoSelector.isInFocus() && hasBviewChanged();
					if (shouldRefresh) {
						logger.info("Gained focus; refreshing");
						ServiceManager.getInstance().updateModelNow();
					}
				});
			}
		});
	}
	
	private boolean hasBviewChanged() {
		if (browserComponent.getCurrentPageSource().equals(currentPageSource)){
			return false;
		}
		currentPageSource = browserComponent.getCurrentPageSource();
		return true;
	}

	private static void initialiseJNA() {
		if (PlatformSpecific.isOnWindows()) {
			mainWindowHandle = User32.INSTANCE.GetForegroundWindow();
		}
	}

	private HashMap<String, String> initialiseCommandLineArguments() {
		Parameters params = getParameters();
		final List<String> parameters = params.getRaw();
		assert parameters.size() % 2 == 0 : "Parameters should come in pairs";
		HashMap<String, String> commandLineArgs = new HashMap<>();
		for (int i=0; i<parameters.size(); i+=2) {
			commandLineArgs.put(parameters.get(i), parameters.get(i+1));
		}
		return commandLineArgs;
	}

	private void quit() {
		ServiceManager.getInstance().stopModelUpdate();
		columns.saveSession();
		DataManager.getInstance().saveLocalConfig();
		DataManager.getInstance().saveSessionConfig();
		browserComponent.onAppQuit();
		Platform.exit();
		System.exit(0);
	}

	private Parent createRoot() throws IOException {<commit_msg>Better variable name.<commit_after>package ui;

import java.awt.Rectangle;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.egit.github.core.IRepositoryIdProvider;
import org.eclipse.egit.github.core.RepositoryId;

import service.ServiceManager;
import storage.DataManager;
import ui.components.HTStatusBar;
import ui.issuecolumn.ColumnControl;
import util.DialogMessage;
import util.PlatformEx;
import util.PlatformSpecific;
import util.Utility;
import util.events.BoardSavedEvent;
import util.events.Event;
import util.events.EventDispatcher;
import util.events.EventHandler;
import util.events.LoginEvent;
import browserview.BrowserComponent;

import com.google.common.eventbus.EventBus;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HWND;

public class UI extends Application implements EventDispatcher {

	private static final int VERSION_MAJOR = 2;
	private static final int VERSION_MINOR = 0;
	private static final int VERSION_PATCH = 1;

	public static final String ARG_UPDATED_TO = "--updated-to";

	private static final double WINDOW_DEFAULT_PROPORTION = 0.6;

	private static final Logger logger = LogManager.getLogger(UI.class.getName());
	private static HWND mainWindowHandle;

	// Main UI elements

	private Stage mainStage;
	private ColumnControl columns;
	private MenuControl menuBar;
	private BrowserComponent browserComponent;
	private RepositorySelector repoSelector;
	
	// Bview changes
	private String pageContentOnLoad = "";

	// Events

	private EventBus events;

	// Application arguments

	private HashMap<String, String> commandLineArgs;

	public static void main(String[] args) {
		Application.launch(args);
	}

	private static UI instance;
	public static UI getInstance() {
		return instance;
	}

	@Override
	public void start(Stage stage) throws IOException {

		instance = this;

		//log all uncaught exceptions
		Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> {
            logger.error(throwable.getMessage(), throwable);
        });

		events = new EventBus();

		repoSelector = createRepoSelector();

		browserComponent = new BrowserComponent(this);
		initCSS();
		mainStage = stage;
		stage.setMaximized(false);
		Scene scene = new Scene(createRoot());
		setupMainStage(scene);
		loadFonts();
		applyCSS(scene);
		getUserCredentials();
		commandLineArgs = initialiseCommandLineArguments();

		DataManager.getInstance();
	}

	private void getUserCredentials() {
		repoSelector.setDisable(true);
		new LoginDialog(mainStage, columns).show().thenApply(success -> {
			if (success) {
				browserComponent.initialise();
				setExpandedWidth(false);
				columns.loadIssues();
				triggerEvent(new LoginEvent());
				repoSelector.setDisable(false);
				repoSelector.refreshComboBoxContents();
				repoSelector.setValue(ServiceManager.getInstance().getRepoId().generateId());
				triggerEvent(new BoardSavedEvent());
			} else {
				quit();
			}
			return true;
		}).exceptionally(e -> {
			logger.error(e.getLocalizedMessage(), e);
			return false;
		});
	}

	private static String CSS = "";

	public void initCSS() {
		CSS = this.getClass().getResource("hubturbo.css").toString();
	}

	public static void applyCSS(Scene scene) {
		scene.getStylesheets().clear();
		scene.getStylesheets().add(CSS);
	}

	public static void loadFonts(){
		Font.loadFont(UI.class.getResource("/resources/octicons/octicons-local.ttf").toExternalForm(), 32);
	}

	private void setupMainStage(Scene scene) {
		mainStage.setTitle("HubTurbo " + Utility.version(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH));
		mainStage.setScene(scene);
		mainStage.show();
		mainStage.setOnCloseRequest(e -> quit());
		initialiseJNA();
		mainStage.focusedProperty().addListener(new ChangeListener<Boolean>() {
			@Override
			public void changed(ObservableValue<? extends Boolean> unused, Boolean wasFocused, Boolean isFocused) {
				if (!isFocused) {
					return;
				}
				if (PlatformSpecific.isOnWindows()) {
					browserComponent.focus(mainWindowHandle);
				}
				PlatformEx.runLaterDelayed(() -> {
					// A refresh is triggered if:
					// 1. Repo-switching is not disabled (meaning an update is not in progress)
					// 2. The repo-switching box is not in focus (clicks on it won't trigger this)
					boolean shouldRefresh = isRepoSwitchingAllowed() && !repoSelector.isInFocus() && hasBviewChanged();
					if (shouldRefresh) {
						logger.info("Gained focus; refreshing");
						ServiceManager.getInstance().updateModelNow();
					}
				});
			}
		});
	}
	
	private boolean hasBviewChanged() {
		if (browserComponent.getCurrentPageSource().equals(pageContentOnLoad)){
			return false;
		}
		pageContentOnLoad = browserComponent.getCurrentPageSource();
		return true;
	}

	private static void initialiseJNA() {
		if (PlatformSpecific.isOnWindows()) {
			mainWindowHandle = User32.INSTANCE.GetForegroundWindow();
		}
	}

	private HashMap<String, String> initialiseCommandLineArguments() {
		Parameters params = getParameters();
		final List<String> parameters = params.getRaw();
		assert parameters.size() % 2 == 0 : "Parameters should come in pairs";
		HashMap<String, String> commandLineArgs = new HashMap<>();
		for (int i=0; i<parameters.size(); i+=2) {
			commandLineArgs.put(parameters.get(i), parameters.get(i+1));
		}
		return commandLineArgs;
	}

	private void quit() {
		ServiceManager.getInstance().stopModelUpdate();
		columns.saveSession();
		DataManager.getInstance().saveLocalConfig();
		DataManager.getInstance().saveSessionConfig();
		browserComponent.onAppQuit();
		Platform.exit();
		System.exit(0);
	}

	private Parent createRoot() throws IOException {
{'fraction_non_alphanumeric': 0.11368567885926845, 'fraction_numerical': 0.003874767513949163, 'mean_word_length': 4.914298808432631, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5725345', 'n_tokens_mistral': 4179, 'n_tokens_neox': 3761, 'n_words': 840}