package com.openfin.desktop.demo;

import com.openfin.desktop.*;
import com.openfin.desktop.ActionEvent;
import com.openfin.desktop.Window;
import com.sun.jna.Native;
import info.clearthought.layout.TableLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.System;

/**
 * Java example to embed HTML5 window in Swing window
 *
 * Created by wche on 3/13/15.
 *
 */
public class WindowEmbedDemo extends JPanel implements ActionListener, WindowListener {
    private final static Logger logger = LoggerFactory.getLogger(WindowEmbedDemo.class.getName());

    private static JFrame jFrame;
    protected String appUuid = "JavaEmbedding";
    protected String startupUuid = "OpenFinHelloWorld";
    protected DesktopConnection desktopConnection;

    protected String openfin_app_url = "https://cdn.openfin.co/examples/junit/SimpleDockingExample.html";  // source is in release/SimpleDockingExample.html

    protected JButton launch, close;
    protected java.awt.Canvas embedCanvas;
    protected Long previousPrarentHwndId;

    public WindowEmbedDemo(final String startupUuid) {
        this.startupUuid = startupUuid;
        try {
            this.desktopConnection = new DesktopConnection(appUuid);
        } catch (DesktopException desktopError) {
            desktopError.printStackTrace();
        }
        setLayout(new BorderLayout());
        add(layoutCenterPanel(), BorderLayout.CENTER);
        setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        setMainButtonsEnabled(false);
    }

    private JPanel layoutCenterPanel() {
        JPanel panel = new JPanel();
        double size[][] = {{TableLayout.FILL}, {120, TableLayout.FILL}};
        panel.setLayout(new TableLayout(size));
        panel.add(layoutActionButtonPanel(), "0,0,0,0");
        panel.add(layoutEmbedPanel(), "0, 1, 0, 1");
        return panel;
    }

    private JPanel layoutActionButtonPanel() {
        JPanel buttonPanel = new JPanel();

        JPanel topPanel = new JPanel();
        double size[][] = {{10, 190, 20, 190, 10}, {25, 10, 25, 10}};
        topPanel.setLayout(new TableLayout(size));
        topPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createBevelBorder(2), "Desktop"));

        launch = new JButton("Launch OpenFin");
        launch.setActionCommand("start");
        close = new JButton("Shutdown OpenFin");
        close.setActionCommand("close");
        topPanel.add(launch, "1,0,1,0");
        topPanel.add(close, "3,0,3,0");


        close.addActionListener(this);
        launch.addActionListener(this);

        buttonPanel.add(topPanel, "0,0");
        return buttonPanel;
    }

    protected JPanel layoutEmbedPanel() {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createBevelBorder(2), "HTML5 app"));

        embedCanvas = new java.awt.Canvas();
        panel.add(embedCanvas, BorderLayout.CENTER);

        embedCanvas.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent event) {
                super.componentResized(event);
                Dimension newSize = event.getComponent().getSize();
                try {
                    if (startupHtml5app != null) {
                        startupHtml5app.getWindow().embedComponentSizeChange((int)newSize.getWidth(), (int)newSize.getHeight());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });


        return panel;
    }

    private void setMainButtonsEnabled(boolean enabled) {
        launch.setEnabled(!enabled);
        close.setEnabled(enabled);

        if (enabled) {
            this.desktopConnection.getInterApplicationBus().addSubscribeListener(new SubscriptionListener() {
                public void subscribed(String uuid, String topic) {
                    System.out.println("subscribed " + uuid + " on topic " + topic);
                }

                public void unsubscribed(String uuid, String topic) {
                    System.out.println("unsubscribed " + uuid + " on topic " + topic);

                }
            });
        }
    }

    private static void createAndShowGUI(final String startupUuid) {
        //Create and set up the window.
        jFrame = new JFrame("Java Embedding Demo");
//        jFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        //Create and set up the content pane.
        WindowEmbedDemo newContentPane = new WindowEmbedDemo(startupUuid);
        newContentPane.setOpaque(true); //content panes must be opaque
        jFrame.setContentPane(newContentPane);
        jFrame.addWindowListener(newContentPane);
        //Display the window.
        jFrame.pack();
        jFrame.setSize(800, 800);
        jFrame.setLocationRelativeTo(null);
        jFrame.setResizable(true);
        jFrame.setVisible(true);
    }

    private void closeEmbeddedApp() {
        if (this.startupHtml5app != null) {
            try {
                this.startupHtml5app.close();
                this.startupHtml5app = null;
            } catch (DesktopException e) {
                e.printStackTrace();
            }
        }
    }
    
    private void closeDesktop() {
        this.closeEmbeddedApp();
        
        if (desktopConnection != null && desktopConnection.isConnected()) {
            try {
//                new com.openfin.desktop.System(desktopConnection).exit();
                System.out.println("disconnecting ");
                desktopConnection.disconnect();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //closeWebSocket();
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                jFrame.dispose();
            }
        });
        try {
            Thread.sleep(1000);
            java.lang.System.exit(0);
        } catch (InterruptedException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

    @Override
    public void windowOpened(WindowEvent e) {
    }

    @Override
    public void windowClosing(WindowEvent e) {
        closeDesktop();
    }

    @Override
    public void windowClosed(WindowEvent e) {
    }

    @Override
    public void windowIconified(WindowEvent e) {
    }

    @Override
    public void windowDeiconified(WindowEvent e) {
    }

    @Override
    public void windowActivated(WindowEvent e) {
    }

    @Override
    public void windowDeactivated(WindowEvent e) {
    }

    public void actionPerformed(java.awt.event.ActionEvent e) {
        if ("start".equals(e.getActionCommand())) {
            runStartAction();
        } else if ("close".equals(e.getActionCommand())) {
            closeDesktop();
        } else if ("embed-window".equals(e.getActionCommand())) {
            embedStartupApp();
        }
    }

    private void runStartAction() {
        try {
            DesktopStateListener listener = new DesktopStateListener() {
                @Override
                public void onReady() {
                    setMainButtonsEnabled(true);
                    launchHtmlApp();
                }

                @Override
                public void onClose(String error) {
                }

                @Override
                public void onError(String reason) {

                }
                @Override
                public void onMessage(String message) {
                }
                @Override
                public void onOutgoingMessage(String message) {
                }
            };
            RuntimeConfiguration configuration = new RuntimeConfiguration();
            configuration.setAdditionalRuntimeArguments(" --v=1 ");  // enable additional logging from Runtime
            String desktopVersion = java.lang.System.getProperty("com.openfin.demo.version");
            if (desktopVersion == null) {
                desktopVersion = "stable";
            }
            configuration.setRuntimeVersion(desktopVersion);
            desktopConnection.connect(configuration, listener, 60);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void launchHtmlApp() {
            // launch 5 instances of same example app
            int width = 500, height=500;
            try {
                String url = java.lang.System.getProperty("com.openfin.demo.embed.URL");
                if (url != null) {
                    openfin_app_url = url;
                }
                ApplicationOptions options = new ApplicationOptions(startupUuid, startupUuid, openfin_app_url);
                options.setApplicationIcon("http://openfin.github.io/snap-and-dock/openfin.ico");
                WindowOptions mainWindowOptions = new WindowOptions();
                mainWindowOptions.setAutoShow(false);
                mainWindowOptions.setDefaultHeight(height);
                mainWindowOptions.setDefaultLeft(10);
                mainWindowOptions.setDefaultTop(50);
                mainWindowOptions.setDefaultWidth(width);
                mainWindowOptions.setShowTaskbarIcon(true);
                mainWindowOptions.setSaveWindowState(false);  // set to false so all windows start at same initial positions for each run
                mainWindowOptions.setFrame(false);
                mainWindowOptions.setContextMenu(true);
                mainWindowOptions.setResizeRegionSize(0);        // need this to turn off resize region for embedded (child) window
                options.setMainWindowOptions(mainWindowOptions);
                DemoUtils.runApplication(options, this.desktopConnection,  new AckListener() {
                    @Override
                    public void onSuccess(Ack ack) {
                        Application app = (Application) ack.getSource();
                        try {
                            Thread.sleep(1000);
                            embedStartupApp();
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                    @Override
                    public void onError(Ack ack) {
                        logger.error(String.format("Error launching %s %s", options.getUUID(), ack.getReason()));
                    }
                });
            } catch (Exception e) {
                logger.error("Error launching app", e);
            }
    }

    private boolean trayIconAdded = false;
    private Application startupHtml5app;

    private void embedStartupApp() {
        try {
            if (startupHtml5app == null) {
                startupHtml5app = Application.wrap(this.startupUuid, this.desktopConnection);
            }
            if (!trayIconAdded) {
                startupHtml5app.setTrayIcon("http://icons.iconarchive.com/icons/marcus-roberto/google-play/512/Google-Search-icon.png", new EventListener() {
                    public void eventReceived(ActionEvent actionEvent) {
                        java.lang.System.out.println("Tray icon clicked");
                    }
                }, null);
                trayIconAdded = true;
            } else {
                startupHtml5app.removeTrayIcon(null);
                trayIconAdded = false;
            }

            Window html5Wnd = startupHtml5app.getWindow();
            long parentHWndId = Native.getComponentID(this.embedCanvas);
            System.out.println("Canvas HWND " + Long.toHexString(parentHWndId));
            html5Wnd.embedInto(parentHWndId, this.embedCanvas.getWidth(), this.embedCanvas.getHeight(), new AckListener() {
                @Override
                public void onSuccess(Ack ack) {
                    if (ack.isSuccessful()) {
                        previousPrarentHwndId = ack.getJsonObject().getLong("hWndPreviousParent");
                    } else {
                        java.lang.System.out.println("embedding failed: " + ack.getJsonObject().toString());
                    }
                }
                @Override
                public void onError(Ack ack) {
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        java.lang.System.out.println("starting: ");
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI("OpenFin Embed Example");
            }
        });
    }
}