package ui;

import java.awt.Desktop;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.net.URISyntaxException;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import model.Model;
import model.TurboIssue;
import model.TurboUser;

public class IssuePanelCell extends ListCell<TurboIssue> {

	private static final String STYLE_ISSUE_NAME = "-fx-font-size: 24px;";

	private final Stage mainStage;
	private final Model model;
	
	public IssuePanelCell(Stage mainStage, Model model, IssuePanel parent) {
		super();
		this.mainStage = mainStage;
		this.model = model;
		Font.loadFont(getClass().getResource("octicons-local.ttf").toExternalForm(), 24);

	}

	@Override
	public void updateItem(TurboIssue issue, boolean empty) {
		super.updateItem(issue, empty);
		if (issue == null)
			return;
		
		HBox buttonBox = new HBox();
		Label ghIcon = new Label();
		ghIcon.setStyle("-fx-font-family: github-octicons; -fx-font-size: 22px; -fx-background-color: transparent; -fx-padding: 0 5 0 0;");
		ghIcon.setText("G");
		buttonBox.getChildren().addAll(ghIcon);
		buttonBox.setOnMouseClicked((MouseEvent e) -> {
			browse(issue.getHtmlUrl());
		});
		
		Text issueName = new Text("#" + issue.getId() + " " + issue.getTitle());
		issueName.setStyle(STYLE_ISSUE_NAME + "-fx-strikethrough: " + !issue.getOpen() + ";");
		issue.titleProperty().addListener(new ChangeListener<String>() {
			@Override
			public void changed(
					ObservableValue<? extends String> stringProperty,
					String oldValue, String newValue) {
				issueName.setText("#" + issue.getId() + " " + newValue);
			}
		});
		
		HBox titleBox = new HBox();
		titleBox.getChildren().addAll(buttonBox, issueName);

		ParentIssuesDisplayBox parents = new ParentIssuesDisplayBox(issue.getParents(), false);
		
		LabelDisplayBox labels = new LabelDisplayBox(issue.getLabels(), false);

		TurboUser assignee = issue.getAssignee();
		HBox assigneeBox = new HBox();
		if (assignee != null) {
			assigneeBox.setSpacing(3);
			Text assignedToLabel = new Text("Assigned to:");
			Text assigneeName = new Text(assignee.getGithubName());
			assigneeBox.getChildren().addAll(assignedToLabel, assigneeName);
		}

		VBox everything = new VBox();
		everything.setSpacing(2);
		everything.getChildren().addAll(titleBox, parents);
		if (assignee != null) everything.getChildren().add(assigneeBox);
		everything.getChildren().add(labels);

		setGraphic(everything);

		setStyle(UI.STYLE_BORDERS + "-fx-border-radius: 5;");

		registerEvents(issue);
	}
	
	private void browse(String htmlUrl) {
		
		if (htmlUrl == null || htmlUrl.isEmpty()) return;

		final String osName = System.getProperty("os.name");
		
		if (osName.startsWith("Mac OS") || osName.startsWith("Windows")) {
			browseWithDesktop(htmlUrl);
		} else {
			// Assume *nix
			browseUnix(htmlUrl);
		}
	}
	
	private void browseWithDesktop(String htmlUrl) {
		try {
			if (Desktop.isDesktopSupported()) {
		        Desktop desktop = Desktop.getDesktop();
		        if (desktop.isSupported(Desktop.Action.BROWSE)) {

		            URI uri = new URI(htmlUrl);
		            desktop.browse(uri);
		        }
	        }
	    } catch (IOException ex) {
	        ex.printStackTrace();
	    } catch (URISyntaxException ex) {
	        ex.printStackTrace();
	    }
	}

	private void browseUnix(String url) {

		final String[] UNIX_BROWSE_CMDS = new String[] {"google-chrome", "firefox", "www-browser", "opera", "konqueror", "epiphany", "mozilla", "netscape", "w3m", "lynx" };
		for (final String cmd : UNIX_BROWSE_CMDS) {
			
			if (unixCommandExists(cmd)) {
				try {
					Runtime.getRuntime().exec(new String[] {cmd, url.toString()});
				} catch (IOException e) {
				}
				return;
			}
		}
	}

	private static boolean unixCommandExists(final String cmd) {
		Process whichProcess;
		try {
			whichProcess = Runtime.getRuntime().exec(new String[] { "which", cmd });
			boolean finished = false;
			do {
				try {
					whichProcess.waitFor();
					finished = true;
				} catch (InterruptedException e) {
					return false;
				}
			} while (!finished);

			return whichProcess.exitValue() == 0;
		} catch (IOException e1) {
			return false;
		}
	}

	private void registerEvents(TurboIssue issue) {
		WeakReference<TurboIssue> issueRef = new WeakReference<TurboIssue>(issue);
		setOnMouseClicked((MouseEvent mouseEvent) -> {
			if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
				if (mouseEvent.getClickCount() == 2) {
					onDoubleClick(issueRef.get());
				}
			}
		});
	}

	private void onDoubleClick(TurboIssue issue) {
		TurboIssue modifiedIssue = new TurboIssue(issue);
		(new IssueDialog(mainStage, model, modifiedIssue)).show().thenApply(
				response -> {
					if (response.equals("ok")) {
						model.updateIssue(issue, modifiedIssue);
					}
					return true;
				});
	}
}

@@ -1687,16 +1687,96 @@
 + %22;%22);%0A
+%09%09%0A%09%09WeakReference%3CTurboIssue%3E issueRef = new WeakReference%3CTurboIssue%3E(issue);%0A
 %09%09issue.
@@ -1992,32 +1992,41 @@
 Text(%22#%22 + issue
+Ref.get()
 .getId() + %22 %22 +

use weak reference to issue in change listener of issue cell