package org.jboss.installer.navigation;

import java.util.ArrayList;
import java.util.List;

/**
 * The state of navigation buttons. Can be used to hide/show and enable/disable navigation buttons.
 */
public class NavigationState implements ScreenNavState {
    private boolean nextEnabled = true;
    private boolean nextVisible = true;
    private boolean previousEnabled = true;
    private boolean previousVisible = true;
    private boolean quitVisible = true;
    private boolean doneVisible = false;

    private boolean errorState = false;
    private boolean focus = true;

    private List<Observer> observers = new ArrayList<>();

    public boolean isNextEnabled() {
        return nextEnabled;
    }

    public boolean isPreviousEnabled() {
        return previousEnabled;
    }

    /**
     * Update the focus state. Does not send an event.
     */
    public void lostFocus() {
        this.focus = false;
    }

    public boolean isFocus() {
        return focus;
    }

    /**
     * {@link Observer#changed()} will be called when one or more buttons change their state.
     */
    public interface Observer {
        void changed();
    }

    // Screens support
    @Override
    public void setNextEnabled(boolean enabled) {
        if (this.nextEnabled != enabled) {
            this.nextEnabled = enabled;
            fireEvent();
        }
    }

    // Navigator

    /**
     * set focus on quit button
     */
    public void setErrorState() {
        if (!errorState) {
            errorState = true;
            fireEvent();
        }
    }

    public boolean isErrorState() {
        return errorState;
    }

    @Override
    public void requestFocus() {
        if (!this.focus) {
            this.focus = true;
            fireEvent();
        }
    }

    /**
     * toggle display/hide Next button
     * @param visible
     */
    public void setNextVisible(boolean visible) {
        if (this.nextVisible != visible) {
            this.nextVisible = visible;
            fireEvent();
        }
    }

    /**
     * toggle display/hide Previous button
     * @param visible
     */
    public void setPreviousVisible(boolean visible) {
        if (this.previousVisible != visible) {
            this.previousVisible = visible;
            fireEvent();
        }
    }

    public void setQuitVisible(boolean visible) {
        if (this.quitVisible != visible) {
            this.quitVisible = visible;
            fireEvent();
        }
    }

    public void setDoneVisible(boolean visible) {
        if (this.doneVisible != visible) {
            this.doneVisible = visible;
            fireEvent();
        }
    }

    @Override
    public void setPreviousEnabled(boolean enabled) {
        if (this.previousEnabled != enabled) {
            this.previousEnabled = enabled;
            fireEvent();
        }
    }

    /**
     * reset to default state. All buttons will be made visible and enabled.
     */
    public void reset() {
        // only fire the event if there are any changes
        if (!this.nextVisible || !this.nextEnabled || !this.previousVisible || !this.previousEnabled) {
            this.nextEnabled = true;
            this.nextVisible = true;
            this.previousEnabled = true;
            this.previousVisible = true;
            fireEvent();
        }
    }

    // used by NavigationPanel
    public boolean isNextVisible() {
        return nextVisible;
    }

    public boolean isPreviousVisible() {
        return previousVisible;
    }

    public boolean isQuitVisible() {
        return quitVisible;
    }

    public boolean isDoneVisible() {
        return doneVisible;
    }

    /**
     * register observers to be notified of navigation state changes.
     * @param consumer
     */
    public void registerObserver(Observer consumer) {
        observers.add(consumer);
    }

    private void fireEvent() {
        observers.forEach(Observer::changed);
    }
}
