package me.coley.recaf.ui;

import java.util.List;
import java.util.stream.Collectors;

import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import me.coley.recaf.Logging;
import me.coley.recaf.ui.component.ActionButton;
import me.coley.recaf.util.Icons;
import me.coley.recaf.util.JavaFX;
import me.coley.recaf.util.Lang;
import me.coley.recaf.util.SelfReference;

/**
 * Window for handling attaching to external processes.
 * 
 * @author Matt
 */
public class FxAttach extends Stage {
	private final static FxAttach INSTANCE = new FxAttach();
	private final ListView<VirtualMachineDescriptor> list = new ListView<>();
	private VirtualMachineDescriptor selected;

	private FxAttach() {
		setTitle(Lang.get("ui.attach"));
		getIcons().add(Icons.ATTACH);
		Button btn = new ActionButton(Lang.get("ui.attach.prompt"), () -> {
			attach(selected);
		});
		btn.setDisable(true);
		list.setCellFactory(param -> new ListCell<VirtualMachineDescriptor>() {
			@Override
			public void updateItem(VirtualMachineDescriptor item, boolean empty) {
				super.updateItem(item, empty);
				if (empty || item == null) {
					setGraphic(null);
					setText(null);
				} else {
					setGraphic(null);
					setText(item.displayName());
				}
			}
		});
		list.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
			selected = newValue;
			boolean set = selected != null;
			btn.setDisable(!set);
			if (set) {
				btn.setText(selected.displayName());
			} else {
				btn.setText(Lang.get("ui.attach.prompt"));
			}
		});
		BorderPane bp = new BorderPane();
		bp.setCenter(list);
		bp.setBottom(btn);
		refresh();
		setScene(JavaFX.scene(bp, 700, 200));
	}

	private void refresh() {
		List<VirtualMachineDescriptor> vms = VirtualMachine.list();
		//@formatter:off
		// Skip self, show normal VMs.
		vms = vms.stream()
				.filter(vm -> 
					 vm.displayName().length() > 1 && 
					!vm.displayName().startsWith("me.coley.recaf")
				).collect(Collectors.toList());
		//@formatter:on
		list.getItems().clear();
		list.getItems().addAll(vms);
	}

	private static void attach(VirtualMachineDescriptor vmDesc) {
		// The attach process is threaded so that the target vm's agent does not
		// lock up the current instance of Recaf.
		// Without threading, the client locks until the agent is terminated.
		new Thread(() -> {
			try {
				VirtualMachine vm = VirtualMachine.attach(vmDesc);
				vm.loadAgent(SelfReference.get().getPath(), "-agent");
				vm.detach();
			} catch (Exception e) {
				Logging.error(e);
			}
		}).start();
	}

	/**
	 * Display config window.
	 */
	public static void open() {
		if (INSTANCE.isShowing()) {
			INSTANCE.toFront();
		} else {
			INSTANCE.show();
		}
		// refresh VM list
		INSTANCE.refresh();
	}
}

@@ -384,24 +384,53 @@
 af.Logging;%0A
+import me.coley.recaf.Recaf;%0A
 import me.co
@@ -2202,16 +2202,96 @@
 %22)%0A%09%09%09%09)
+.filter(vm -%3E %0A%09%09%09%09%09!vm.displayName().startsWith(%22recaf-%22 + Recaf.VERSION))%0A%09%09%09%09
 .collect

Fix self (Recaf) showing up in attach menu when running via 'java -jar' vs 'java -cp recaf.jar'