/**
 * Copyright (c) 2018, Intel Corporation
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Intel Corporation nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.intel.stl.util.jvm;

import java.awt.Color;
import java.awt.Desktop;
import java.awt.Font;
import java.net.URI;

import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;

/**
 * JavaVersionChecker is invoked before invoking the FM GUI to verify that the
 * JVM in use supports the minimum features required for the application. It
 * uses the JVM's class version to check this; In general, we should avoid tying
 * the application to a specific JVM version because it is expected that the JVM
 * will be updated regularly for security reasons (Oracle Java sets up the PATH
 * to always invoke the latest update). Because of this, the scripts that start
 * the application (generated by Gradle) use whatever version is available in
 * the PATH but provide a way to use a specific Java version by setting
 * JAVA_HOME. This is why it is better to check for Java version at invocation
 * time rather than at installation time.
 *
 * This class should be compiled with target compatibility as low as possible.
 * Currently it has been set to Java 5 (see the Gradle build for this
 * subproject), which means this class will run under a JVM as older as J2SE 5.0
 * (released in 2004). Older JVM versions would result in exception
 * java.lang.UnsupportedClassVersionError being thrown.
 */
public class JavaVersionChecker {

    private static final String JAVA_DOWNLOAD_URL = "http://java.com/";

    protected static final String JAVA_CLASS_VERSION = "java.class.version";

    /*-
     * Historic Java class versions:
     *   Java 1.2 = 46 (1998)
     *   Java 1.3 = 47 (2000)
     *   Java 1.4 = 48 (2002)
     *   Java 5   = 49 (2004)
     *   Java 6   = 50 (2006)
     *   Java 7   = 51 (2011)
     *   Java 8   = 52 (2014)
     *   Java 9   = 53 (2017)
     *   Java 10  = 54 (2018)
     */
    protected double lowestVersionSupported = 52.0; // Java 1.8

    private final String lowestVersionSupportedStr = "Java 8";

    protected JavaVersionChecker() {
    }

    protected int verifyJavaClassVersion(String[] args) {
        int rc = 0;
        boolean showWarning = false;
        if (args.length == 1 && args[0].equals("warn")) {
            showWarning = true;
        }
        String jvmClsVersion = System.getProperty(JAVA_CLASS_VERSION);
        try {
            double jvmVersion = Double.parseDouble(jvmClsVersion);
            if (jvmVersion < lowestVersionSupported) {
                rc = 1;
                if (showWarning) {
                    showWarning();
                }
            }
        } catch (NumberFormatException e) {
            rc = 12;
        }

        return rc;
    }

    private void showWarning() {
        String javaVersion = System.getProperty("java.version");

        String contents = getJavaVersionErrorMessage(javaVersion);
        final JEditorPane pane = new JEditorPane("text/html", contents);
        pane.setBorder(null);
        pane.addHyperlinkListener(new HyperlinkListener() {

            public void hyperlinkUpdate(HyperlinkEvent evt) {
                if (evt.getEventType()
                        .equals(HyperlinkEvent.EventType.ACTIVATED)
                        && Desktop.isDesktopSupported()) {
                    URI url;
                    try {
                        url = new URI(JAVA_DOWNLOAD_URL);
                        Desktop.getDesktop().browse(url);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        pane.setEditable(false);
        showMessageDialog(pane);
    }

    private String getJavaVersionErrorMessage(String javaVersion) {
        StringBuilder msg = new StringBuilder();
        JLabel label = new JLabel();
        Font font = label.getFont();
        Color color = label.getBackground();
        msg.append("<html><body style=\"font-family:");
        msg.append(font.getFamily());
        msg.append("; font-weight:");
        msg.append(font.isBold() ? "bold" : "normal");
        msg.append("; font-size:");
        msg.append(font.getSize());
        msg.append("pt; background-color: rgb(");
        msg.append(color.getRed());
        msg.append(",");
        msg.append(color.getGreen());
        msg.append(",");
        msg.append(color.getBlue());
        msg.append(");\">");
        msg.append("<p>This version of Java (");
        msg.append(javaVersion);
        msg.append(") is not supported by OPA FM GUI;</p>");
        msg.append("<p>please go to <a href=\"");
        msg.append(JAVA_DOWNLOAD_URL);
        msg.append("\">");
        msg.append(JAVA_DOWNLOAD_URL);
        msg.append("</a> to download ");
        msg.append(lowestVersionSupportedStr);
        msg.append(" or higher<p>");
        msg.append("</body></html>");
        return msg.toString();
    }

    protected void showMessageDialog(final JEditorPane pane) {
        // enable anti-aliased text
        System.setProperty("awt.useSystemAAFontSettings", "on");
        System.setProperty("swing.aatext", "true");
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            if (System.getProperty("os.name").equals("Linux")) {
                UIManager.setLookAndFeel(
                        UIManager.getCrossPlatformLookAndFeelClassName());
            }
            SwingUtilities.invokeAndWait(new Runnable() {

                public void run() {
                    JOptionPane.showMessageDialog(null, pane,
                            "Java version not supported",
                            JOptionPane.ERROR_MESSAGE);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        JavaVersionChecker checker = new JavaVersionChecker();
        int status = checker.verifyJavaClassVersion(args);
        System.exit(status);
    }

}
