package de.renew.splashscreen.impl;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import javax.swing.JWindow;

import org.apache.log4j.Logger;


/**
 * This class creates the splashscreen. The splashscreen is composed by a given
 * background image panel and the {@link ExtendedProgressBar}.
 *
 * @author Eva Mueller
 */
public final class RenewSplashScreen extends JPanel {
    private static final Logger LOGGER = Logger.getLogger(RenewSplashScreen.class);

    private static final String SPLASH_BACKGROUND = "splashscreen.png";
    private static final Dimension DIMENSION = new Dimension(500, 500);
    private static final int PROGRESS_BAR_PARTS = 6;
    private static final int PROGRESS_BAR_Y = 150;
    private static final int PROGRESS_BAR_HEIGHT = 300;
    private static final double PROGRESS_BAR_WIDTH = 1.5;
    private static final int SPLASH_MARGIN = 10;
    private static final int SPLASH_SCREEN_CLOSE_DELAY = 500;

    private static BufferedImage _img = null;
    private static JWindow _splashScreen;
    private static RenewSplashScreen _renewSplashScreen;
    /**
     * The progress bar component used to display the plug-in loading progress.
     */
    private ExtendedProgressBar _extendedProgressBar;
    /**
     * The panel that displays the background image of the splash screen.
     */
    private ImagePanel _imgPanel;

    /**
     * Private constructor to create singleton instance of this class.<br>
     */
    private RenewSplashScreen() {
        if (_renewSplashScreen == null) {
            _extendedProgressBar = ExtendedProgressBar.getInstance();
            _renewSplashScreen = this;
        }
    }

    /**
     * Get (singleton) instance of the {@code RenewSplashScreen}.
     *
     * @return the current instance of  {@code RenewSplashScreen}
     */
    public static synchronized RenewSplashScreen getInstance() {
        if (_renewSplashScreen == null) {
            try {
                _renewSplashScreen = new RenewSplashScreen();
            } catch (NoClassDefFoundError e) {
                LOGGER.trace("Splash screen setup: Caught " + e);
                // This is a hack to fail more gracefully on unix systems
                // where the DISPLAY variable is configured to an
                // inaccessible X server.
                String reason = e.getMessage();
                if (reason != null && reason.contains("sun.awt.X11GraphicsEnvironment")) {
                    LOGGER.info(
                        "Splash screen deactivated by NoClassDefFoundError: " + e.getMessage()
                            + "\nProbably the DISPLAY variable points to an inaccessible X server."
                            + "\nPlease check the variable and the X server configuration.");
                    // stay with default return value: null
                } else {
                    throw e;
                }
            }
        }
        return _renewSplashScreen;
    }

    /**
     * Create and show the splashscreen.
     */
    public void showSplashScreen() {
        try {
            LOGGER.debug("Setting up splash screen.");
            createBackgroundImage();
            _splashScreen = new JWindow();
            _splashScreen.setSize(DIMENSION);
            _splashScreen.setLayout(null);
            _splashScreen.setBackground(Color.WHITE);
            Container contentPane = _splashScreen.getContentPane();
            contentPane.setBackground(Color.WHITE);

            // progressbar
            _extendedProgressBar.setBounds(
                DIMENSION.width / PROGRESS_BAR_PARTS, PROGRESS_BAR_Y,
                (int) (DIMENSION.width / PROGRESS_BAR_WIDTH), PROGRESS_BAR_HEIGHT);
            contentPane.add(_extendedProgressBar);

            // background image
            contentPane.add(_imgPanel);

            _splashScreen.validate();
            _splashScreen.setLocationRelativeTo(null);
            _splashScreen.setVisible(true);
            _splashScreen.toFront();
        } catch (java.awt.HeadlessException e) {
            LOGGER.info("Splash screen deactivated by HeadlessException: " + e.getMessage());
        } catch (Exception e) {
            LOGGER.warn("Exception during splash screen setup: " + e, e);
        }
    }

    /**
     * Close the splashscreen.
     */
    public void closeSplashScreen() {
        if (_splashScreen != null) {
            try {
                Thread.sleep(SPLASH_SCREEN_CLOSE_DELAY);
            } catch (InterruptedException e) {
                LOGGER.debug("Splash screen progress update delay interrupted.  Skipping...");
            }
            LOGGER.debug("Closing splash screen.");
            _splashScreen.dispose();
            _splashScreen = null;
            _extendedProgressBar.closeExtendedProgressBar();
            _extendedProgressBar = null;
            _imgPanel = null;
            _renewSplashScreen = null;
        }
    }

    /**
     * Create background image panel.
     *
     * @author Eva Mueller
     */
    private void createBackgroundImage() throws IOException {
        try (InputStream inputStream = getClass().getResourceAsStream("/" + SPLASH_BACKGROUND)) {
            if (inputStream != null) {
                _img = ImageIO.read(inputStream);
                DIMENSION.setSize(
                    _img.getWidth() + SPLASH_MARGIN * 2, _img.getHeight() + SPLASH_MARGIN * 2);
            }
        }
        _imgPanel = new ImagePanel(_img, DIMENSION);
    }

    /**
     * Used to end information from {@link Splashscreen} to {@link ExtendedProgressBar}.
     * @param evt holds information about the loading status in {@link de.renew.plugin.load.PluginLoaderComposition}
     */
    public void progressBarPropertyChange(PropertyChangeEvent evt) {
        _extendedProgressBar.propertyChange(evt);
    }
}