package de.renew.propertymanagementgui.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import de.renew.propertymanagement.prop.ConfigurableHotkeyProperty;
import de.renew.propertymanagement.prop.ConfigurableProperty;
import de.renew.propertymanagement.prop.ConfigurablePropertyManager;
import de.renew.propertymanagementgui.reactivecomponents.Component;


/**
 * The footer of the settings window. Embeds the action Save and Cancel button.
 */
public class FooterComponent extends Component {

    private static final String SAVE_LOCALLY = "Save locally";
    private static final String SAVE_GLOBALLY = "Save globally";
    private static final int RIGID_AREA_WIDTH = 10;
    private static final int RIGID_AREA_HEIGHT = 0;
    private static final EmptyBorder ACTION_BUTTONS_WRAPPER_BORDER = new EmptyBorder(5, 5, 5, 5);
    public static final String DEFAULT = "Set to default";
    public static final String RESET_ALL = "Reset All";

    private final Runnable _savePropertiesGlobalAction;
    private final Runnable _savePropertiesLocalAction;

    private final ActionListener _closeListener;
    private SaveButtonComponent _saveButtonLocal;
    private SaveButtonComponent _saveButtonGlobal;

    private final Runnable _defaultPropertiesAction;
    private final Runnable _resetPropertiesAction;
    private SaveButtonComponent _defaultAllButton;
    private SaveButtonComponent _resetAllButton;

    /**
     * Creates a new FooterComponent.
     *
     * @param savePropertiesGlobalAction The action to be performed when the save globally button is clicked.
     * @param savePropertiesLocalAction The action to be performed when the save locally button is clicked.
     */
    public FooterComponent(
        Runnable savePropertiesGlobalAction, Runnable savePropertiesLocalAction,
        ActionListener closeListener, Runnable defaultPropertiesAction,
        Runnable resetPropertiesAction)
    {
        _savePropertiesGlobalAction = savePropertiesGlobalAction;
        _savePropertiesLocalAction = savePropertiesLocalAction;
        _closeListener = closeListener;
        _defaultPropertiesAction = defaultPropertiesAction;
        _resetPropertiesAction = resetPropertiesAction;
    }

    @Override
    protected JComponent render() {
        JComponent footer = new JPanel();
        setLayoutForFooter(footer);

        JComponent actionButtonsWrapper = getActionButtonsWrapperIn();
        footer.add(actionButtonsWrapper, BorderLayout.EAST);

        return footer;
    }

    private void setLayoutForFooter(JComponent footer) {
        footer.setMaximumSize(new Dimension(Integer.MAX_VALUE, footer.getPreferredSize().height));
        footer.setLayout(new BorderLayout());
    }

    private JComponent getActionButtonsWrapperIn() {
        JPanel actionButtonsWrapper = new JPanel();
        setLayoutForActionButtonsWrapper(actionButtonsWrapper);

        addActionButtonsToActionButtonsWrapper(actionButtonsWrapper);

        return actionButtonsWrapper;
    }

    private void setLayoutForActionButtonsWrapper(JComponent actionButtonsWrapper) {
        actionButtonsWrapper.setLayout(new BoxLayout(actionButtonsWrapper, BoxLayout.X_AXIS));
        actionButtonsWrapper.setBorder(ACTION_BUTTONS_WRAPPER_BORDER);
    }

    private void addActionButtonsToActionButtonsWrapper(JComponent actionButtonsWrapper) {
        _saveButtonLocal = new SaveButtonComponent(_savePropertiesLocalAction, SAVE_LOCALLY);
        _saveButtonGlobal = new SaveButtonComponent(_savePropertiesGlobalAction, SAVE_GLOBALLY);
        _defaultAllButton = new SaveButtonComponent(_defaultPropertiesAction, DEFAULT);
        _resetAllButton = new SaveButtonComponent(_resetPropertiesAction, RESET_ALL);
        actionButtonsWrapper.add(_saveButtonLocal.get());
        actionButtonsWrapper.add(_saveButtonGlobal.get());
        actionButtonsWrapper.add(_defaultAllButton.get());
        actionButtonsWrapper.add(_resetAllButton.get());

        actionButtonsWrapper
            .add(Box.createRigidArea(new Dimension(RIGID_AREA_WIDTH, RIGID_AREA_HEIGHT)));

        Component closeButton = new CloseButtonComponent(_closeListener);
        actionButtonsWrapper.add(closeButton.get());
    }

    /**
     * React to some change to the settings.
     */
    public void settingsChanged() {
        final ConfigurablePropertyManager propManager = ConfigurablePropertyManager.getInstance();
        _saveButtonGlobal.setEnabled(propManager.hasStagedChanges());
        _saveButtonLocal.setEnabled(propManager.hasStagedChanges());
        _resetAllButton.setEnabled(propManager.hasStagedChanges());
        _defaultAllButton.setEnabled(
            propManager.getConfigurableProperties().values().stream()
                .anyMatch(FooterComponent::checkDefault));
    }

    /**
     * Checks whether the Property is currently in a state, such that the default button should be disabled
     *
     * @param e the Property to check
     * @return true, if the default Button would change the Property.
     */
    private static boolean checkDefault(ConfigurableProperty e) {
        final ConfigurablePropertyManager propManager = ConfigurablePropertyManager.getInstance();
        if (e instanceof ConfigurableHotkeyProperty eh) {
            return !(propManager.getStagedChange(eh) == null)
                && !eh.getDefaultKeyStroke().equals(propManager.getStagedChange(eh))
                || propManager.getStagedChange(eh) == null && !(eh.isDefault());
        }
        return !(propManager.getStagedChange(e) == null)
            && !e.getDefaultValue().equals(propManager.getStagedChange(e))
            || propManager.getStagedChange(e) == null && !(e.isDefault());
    }
}
