// Path: easyfxml/src/main/java/moe/tristan/easyfxml/model/exception/ExceptionHandler.java
// public final class ExceptionHandler {
// 
//     private static final Logger LOG = LoggerFactory.getLogger(ExceptionHandler.class);
//     private static final double ERROR_FIELD_MARGIN_SIZE = 20.0;
// 
//     private final Throwable exception;
// 
//     /**
//      * Creates an instance with the given exception.
//      *
//      * @param exception The exception to base this instance on
//      */
//     public ExceptionHandler(final Throwable exception) {
//         LOG.debug("Generating ExceptionPane for exception of type {}", exception.getClass());
//         this.exception = exception;
//     }
// 
//     /**
//      * @return The exception in a pane with {@link Throwable#getMessage()} as a label over the stacktrace.
//      */
//     public Pane asPane() {
//         return this.asPane(this.exception.getMessage());
//     }
// 
//     /**
//      * Same as {@link #asPane()} but with a custom error label on top of the stack trace.
//      *
//      * @param userReadableError The custom error message.
//      *
//      * @return The exception in a pane with the custom error message as a label over the stacktrace.
//      */
//     public Pane asPane(final String userReadableError) {
//         LOG.debug("Generating node corresponding to ExceptionPane...");
//         final Label messageLabel = new Label(userReadableError);
//         final TextArea throwableDataLabel = new TextArea(formatErrorMessage(this.exception));
// 
//         AnchorPane.setLeftAnchor(messageLabel, ERROR_FIELD_MARGIN_SIZE);
//         Nodes.centerNode(throwableDataLabel, ERROR_FIELD_MARGIN_SIZE);
//         return new AnchorPane(messageLabel, throwableDataLabel);
//     }
// 
//     public static Pane fromThrowable(final Throwable throwable) {
//         return new ExceptionHandler(throwable).asPane();
//     }
// 
//     /**
//      * Creates a pop-up and displays it based on a given exception, pop-up title and custom error message.
//      *
//      * @param title     The title of the error pop-up
//      * @param readable  The custom label to display on top of the stack trace
//      * @param exception The exception to use
//      *
//      * @return a {@link CompletionStage} to know when the pop-up displayed and have a handle on it.
//      */
//     public static CompletionStage<Stage> displayExceptionPane(
//         final String title,
//         final String readable,
//         final Throwable exception
//     ) {
//         final Pane exceptionPane = new ExceptionHandler(exception).asPane(readable);
//         final CompletionStage<Stage> exceptionStage = Stages.stageOf(title, exceptionPane);
//         return exceptionStage.thenCompose(Stages::scheduleDisplaying);
//     }
// 
//     private static String formatErrorMessage(final Throwable throwable) {
//         return "Message : \n" +
//                throwable.getMessage() +
//                "\nStackTrace:\n" +
//                Arrays.stream(throwable.getStackTrace())
//                      .map(StackTraceElement::toString)
//                      .collect(Collectors.joining("\n"));
//     }
// 
// }


import java.net.URI;
import java.net.URL;
import java.util.function.Consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javafx.application.HostServices;
import moe.tristan.easyfxml.model.exception.ExceptionHandler;
import io.vavr.control.Try;
/*
 * Copyright 2017 - 2019 EasyFXML project and contributors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package moe.tristan.easyfxml.model.system;






/**
 * This class contains some utility methods to open URLs with the default web browser of the user.
 */
@Component
public class BrowserSupport {

    private final HostServices hostServices;

    @Autowired
    public BrowserSupport(HostServices hostServices) {
        this.hostServices = hostServices;
    }

    /**
     * Opens a given URL or a pop-up with the error if it could not do so.
     *
     * @param url The URL as a String. Does not have to conform to {@link URL#URL(String)}.
     *
     * @return a {@link Try} that can be either {@link Try.Success} (and empty) or {@link Try.Failure} and contain an
     * exception.
     *
     * @see Try#onFailure(Consumer)
     */
    public Try<Void> openUrl(final String url) {
        return Try.run(() -> hostServices.showDocument(url))
                  .onFailure(cause -> onException(cause, url));
    }

    /**
     * Opens a given URL or a pop-up with the error if it could not do so.
     *
     * @param url The URL as an {@link URL}.
     *
     * @return a {@link Try} that can be either {@link Try.Success} (and empty) or {@link Try.Failure} and contain an
     * exception.
     *
     * @see Try#onFailure(Consumer)
     */
    public Try<Void> openUrl(final URL url) {
        return Try.of(() -> url)
                  .mapTry(URL::toURI)
                  .map(URI::toString)
                  .flatMap(this::openUrl);
    }

    private void onException(final Throwable cause, final String url) {
// Path: easyfxml/src/main/java/moe/tristan/easyfxml/model/exception/ExceptionHandler.java
// public final class ExceptionHandler {
// 
//     private static final Logger LOG = LoggerFactory.getLogger(ExceptionHandler.class);
//     private static final double ERROR_FIELD_MARGIN_SIZE = 20.0;
// 
//     private final Throwable exception;
// 
//     /**
//      * Creates an instance with the given exception.
//      *
//      * @param exception The exception to base this instance on
//      */
//     public ExceptionHandler(final Throwable exception) {
//         LOG.debug("Generating ExceptionPane for exception of type {}", exception.getClass());
//         this.exception = exception;
//     }
// 
//     /**
//      * @return The exception in a pane with {@link Throwable#getMessage()} as a label over the stacktrace.
//      */
//     public Pane asPane() {
//         return this.asPane(this.exception.getMessage());
//     }
// 
//     /**
//      * Same as {@link #asPane()} but with a custom error label on top of the stack trace.
//      *
//      * @param userReadableError The custom error message.
//      *
//      * @return The exception in a pane with the custom error message as a label over the stacktrace.
//      */
//     public Pane asPane(final String userReadableError) {
//         LOG.debug("Generating node corresponding to ExceptionPane...");
//         final Label messageLabel = new Label(userReadableError);
//         final TextArea throwableDataLabel = new TextArea(formatErrorMessage(this.exception));
// 
//         AnchorPane.setLeftAnchor(messageLabel, ERROR_FIELD_MARGIN_SIZE);
//         Nodes.centerNode(throwableDataLabel, ERROR_FIELD_MARGIN_SIZE);
//         return new AnchorPane(messageLabel, throwableDataLabel);
//     }
// 
//     public static Pane fromThrowable(final Throwable throwable) {
//         return new ExceptionHandler(throwable).asPane();
//     }
// 
//     /**
//      * Creates a pop-up and displays it based on a given exception, pop-up title and custom error message.
//      *
//      * @param title     The title of the error pop-up
//      * @param readable  The custom label to display on top of the stack trace
//      * @param exception The exception to use
//      *
//      * @return a {@link CompletionStage} to know when the pop-up displayed and have a handle on it.
//      */
//     public static CompletionStage<Stage> displayExceptionPane(
//         final String title,
//         final String readable,
//         final Throwable exception
//     ) {
//         final Pane exceptionPane = new ExceptionHandler(exception).asPane(readable);
//         final CompletionStage<Stage> exceptionStage = Stages.stageOf(title, exceptionPane);
//         return exceptionStage.thenCompose(Stages::scheduleDisplaying);
//     }
// 
//     private static String formatErrorMessage(final Throwable throwable) {
//         return "Message : \n" +
//                throwable.getMessage() +
//                "\nStackTrace:\n" +
//                Arrays.stream(throwable.getStackTrace())
//                      .map(StackTraceElement::toString)
//                      .collect(Collectors.joining("\n"));
//     }
// 
// }


// Path: easyfxml/src/main/java/moe/tristan/easyfxml/model/system/BrowserSupport.java
import java.net.URI;
import java.net.URL;
import java.util.function.Consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javafx.application.HostServices;
import moe.tristan.easyfxml.model.exception.ExceptionHandler;
import io.vavr.control.Try;

/*
 * Copyright 2017 - 2019 EasyFXML project and contributors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package moe.tristan.easyfxml.model.system;






/**
 * This class contains some utility methods to open URLs with the default web browser of the user.
 */
@Component
public class BrowserSupport {

    private final HostServices hostServices;

    @Autowired
    public BrowserSupport(HostServices hostServices) {
        this.hostServices = hostServices;
    }

    /**
     * Opens a given URL or a pop-up with the error if it could not do so.
     *
     * @param url The URL as a String. Does not have to conform to {@link URL#URL(String)}.
     *
     * @return a {@link Try} that can be either {@link Try.Success} (and empty) or {@link Try.Failure} and contain an
     * exception.
     *
     * @see Try#onFailure(Consumer)
     */
    public Try<Void> openUrl(final String url) {
        return Try.run(() -> hostServices.showDocument(url))
                  .onFailure(cause -> onException(cause, url));
    }

    /**
     * Opens a given URL or a pop-up with the error if it could not do so.
     *
     * @param url The URL as an {@link URL}.
     *
     * @return a {@link Try} that can be either {@link Try.Success} (and empty) or {@link Try.Failure} and contain an
     * exception.
     *
     * @see Try#onFailure(Consumer)
     */
    public Try<Void> openUrl(final URL url) {
        return Try.of(() -> url)
                  .mapTry(URL::toURI)
                  .map(URI::toString)
                  .flatMap(this::openUrl);
    }

    private void onException(final Throwable cause, final String url) {
        ExceptionHandler.displayExceptionPane(