/*
 * Copyright 2022 Red Hat, Inc. and/or its affiliates
 * and other contributors as indicated by the @author tags.
 *
 * 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 org.jboss.uninstaller;

import org.jboss.installer.core.MnemonicUtils;
import org.jboss.uninstaller.utils.UninstallerException;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;

import static org.jboss.uninstaller.Uninstaller.UNINSTALLER_ERROR;
import static org.jboss.uninstaller.Uninstaller.translations;

public class UninstallerFrame extends JFrame {

    private final Optional<Path> tempPath;
    protected JProgressBar progressBar;
    protected JButton uninstallButton;
    protected JButton quitButton;
    private static final String UNINSTALLER_TITLE = "uninstaller.title";
    private static final String UNINSTALLER_WARNING = "uninstaller.warning";
    private static final String YES = "generic.yes";
    private static final String NO = "generic.no";
    private static final String CANCEL = "uninstaller.cancel";
    private static final String FINISHED = "uninstaller.finished";
    private static final String QUIT = "navigation.quit";
    private static final String UNINSTALL = "uninstaller.uninstall";
    public static final String ERROR_TITLE_KEY = "generic.error.title";
    private final Color buttonsHColor = new Color(230, 230, 230);

    private final MnemonicUtils mnemonicUtils = new MnemonicUtils();

    public UninstallerFrame(Optional<Path> tempPath) throws Exception{
        super();

        this.tempPath = tempPath;

        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        setTitle(translations.getString(UNINSTALLER_TITLE));

        UIManager.put("OptionPane.yesButtonText", translations.getString(YES));
        UIManager.put("OptionPane.noButtonText", translations.getString(NO));
        UIManager.put("OptionPane.cancelButtonText", translations.getString(CANCEL));
        UIManager.put("Button.rollover", true);
        UIManager.put("ComboBoxUI", "MyComboBoxUI");
        UIManager.put("Component.hideMnemonics", false);

        buildGUI();

        this.setIconImages(List.of(
                new ImageIcon(this.getClass().getClassLoader().getResource("img/JFrameIcon16x16.png")).getImage(),
                new ImageIcon(this.getClass().getClassLoader().getResource("img/JFrameIcon32x32.png")).getImage(),
                new ImageIcon(this.getClass().getClassLoader().getResource("img/JFrameIcon64x64.png")).getImage(),
                new ImageIcon(this.getClass().getClassLoader().getResource("img/JFrameIcon128x128.png")).getImage()
        ));

        pack();
        centerFrame(this);
        setResizable(false);
        setVisible(true);
    }

    private void buildGUI() {
        JPanel contentPane = (JPanel) getContentPane();
        GridBagLayout layout = new GridBagLayout();
        contentPane.setLayout(layout);
        contentPane.setBackground(Color.WHITE);
        GridBagConstraints gbConstraints = new GridBagConstraints();
        gbConstraints.insets = new Insets(5, 5, 5, 5);
        // We prepare our action handler
        JLabel warningLabel = new JLabel(translations.getString(UNINSTALLER_WARNING), new ImageIcon(UninstallerFrame.class.getResource("/img/warning.png")), JLabel.TRAILING);
        buildConstraints(gbConstraints, 0, 0, 2, 1, 1.0, 0.0);
        gbConstraints.anchor = GridBagConstraints.WEST;
        gbConstraints.fill = GridBagConstraints.NONE;
        layout.addLayoutComponent(warningLabel, gbConstraints);
        contentPane.add(warningLabel);

        gbConstraints.fill = GridBagConstraints.HORIZONTAL;
        progressBar = new JProgressBar();
        progressBar.setMinimum(0);
        progressBar.setMaximum(100);
        progressBar.setStringPainted(true);
        progressBar.setString(" ");

        gbConstraints.gridy++;
        layout.addLayoutComponent(progressBar, gbConstraints);
        contentPane.add(progressBar);
        uninstallButton = new JButton(translations.getString(UNINSTALL));
        uninstallButton.setBackground(buttonsHColor);
        uninstallButton.setFocusPainted(true);
        uninstallButton.addActionListener(new UninstallAction());
        mnemonicUtils.findMnemonic(uninstallButton.getText()).ifPresent(uninstallButton::setMnemonic);

        gbConstraints.gridy++;
        gbConstraints.fill = GridBagConstraints.NONE;
        gbConstraints.anchor = GridBagConstraints.WEST;
        layout.addLayoutComponent(uninstallButton, gbConstraints);
        contentPane.add(uninstallButton);
        quitButton = new JButton(translations.getString(QUIT));
        quitButton.addActionListener((e)->this.exit());
        mnemonicUtils.findMnemonic(quitButton.getText()).ifPresent(quitButton::setMnemonic);
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent event) {
                UninstallerFrame.this.exit();
            }
        });

        gbConstraints.gridx++;
        gbConstraints.anchor = GridBagConstraints.EAST;
        layout.addLayoutComponent(quitButton, gbConstraints);
        contentPane.add(quitButton);

    }

    private void centerFrame(Window frame) {
        Point center = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
        Dimension frameSize = frame.getSize();
        frame.setLocation(center.x - frameSize.width / 2,
                center.y - frameSize.height / 2 - 10);
    }


    /**
     * The actions events handler.
     */
    class UninstallAction implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            uninstallButton.setEnabled(false);
            final Uninstaller uninstaller = new Uninstaller();
            try {
                uninstaller.actionUninstall(tempPath);
            } catch (IOException | UninstallerException ex) {
                uninstaller.debug(String.format(translations.getString(UNINSTALLER_ERROR), ex.getMessage()), ex);
                showErrorMessage(String.format(translations.getString(UNINSTALLER_ERROR), ex.getMessage()), UninstallerFrame.this);
            }
            progressBar.setVisible(true);
            progressBar.setValue(100);
            progressBar.setString(translations.getString(FINISHED));
        }
    }

    private void buildConstraints(GridBagConstraints gbc, int gx, int gy, int gw, int gh,
                                  double wx, double wy) {
        gbc.gridx = gx;
        gbc.gridy = gy;
        gbc.gridwidth = gw;
        gbc.gridheight = gh;
        gbc.weightx = wx;
        gbc.weighty = wy;
    }

    private static void showErrorMessage(String text, Component parent) {
        final JTextArea ta = wrapText(text);
        JOptionPane.showMessageDialog(parent, ta, translations.getString(UNINSTALLER_ERROR), JOptionPane.ERROR_MESSAGE);
    }

    private static JTextArea wrapText(String text) {
        final JTextArea ta = new JTextArea();
        ta.setEditable(false);
        ta.setText(text);
        ta.setBackground(Color.WHITE);
        return ta;
    }

    private void exit() {
        // dispose of all the frames to release the resources
        for (Frame frame : this.getFrames()) {
            frame.dispose();
        }
        this.dispose();

        // still need to call System.exit because the testing framework (jemmy)
        // the TS requires the installer to be run in the same JVM as the tests, making 'dispose' never exit
        System.exit(0);
    }
}
