package be.iminds.ilabt.jfed.ui.javafx.log_gui;

import be.iminds.ilabt.jfed.call_log_output.SerializableApiCallDetails;
import be.iminds.ilabt.jfed.highlevel.history.ApiCallHistory;
import be.iminds.ilabt.jfed.ui.javafx.FXMLUtil;
import be.iminds.ilabt.jfed.ui.javafx.GlyphUtils;
import be.iminds.ilabt.jfed.ui.javafx.style.StyleHelper;
import be.iminds.ilabt.jfed.util.GeniUrn;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import org.controlsfx.glyphfont.FontAwesome;

/**
 * LogHistoryPanel
 * <p/>
 * TODO filters for logging
 * TODO follow and no follow mode
 * TODO no follow mode is a must
 * <p/>
 * TODO make another panel "CallHistoryPanel" that links calls with their results and shows history/ongoing/future calls
 */
public class LogHistoryPanel extends BorderPane {
    @FXML
    private ComboBox<SerializableApiCallDetails> logChooser;
    @FXML
    private ToggleButton showNewCheckbox;

    @FXML
    private LogPanel logPanelController;

    private ObservableList<SerializableApiCallDetails> history;
    private BooleanProperty authShowLast;
    private BooleanProperty authShowLastVisible;
    private ListChangeListener<SerializableApiCallDetails> apiChangeListener = null;


    public LogHistoryPanel(){
        FXMLUtil.injectFXML(this);
    }

    @FXML
    private void initialize() {

        logChooser.setCellFactory(list -> new ApiCallDetailsCell());
        logChooser.setButtonCell(new ApiCallDetailsCell());

        logPanelController.shownLogProperty().bind(logChooser.getSelectionModel().selectedItemProperty());

        authShowLast = showNewCheckbox.selectedProperty();
        authShowLast.set(true);

        authShowLastVisible = showNewCheckbox.visibleProperty();
        authShowLastVisible.setValue(true);
        showNewCheckbox.managedProperty().bind(showNewCheckbox.visibleProperty());
    }

    public BooleanProperty autoShowLastProperty() {
        return authShowLast;
    }

    public boolean isAutoShowLast() {
        return authShowLast.get();
    }

    public void setAutoShowLast(boolean val) {
        authShowLast.set(val);
    }

    public boolean getAuthShowLastVisible() {
        return authShowLastVisible.get();
    }

    public BooleanProperty authShowLastVisibleProperty() {
        return authShowLastVisible;
    }

    public void setAuthShowLastVisible(boolean authShowLastVisible) {
        this.authShowLastVisible.set(authShowLastVisible);
    }

    public void clearApiCallHistory() {
        if (this.history != null) {
            history.removeListener(apiChangeListener);
            apiChangeListener = null;
            logChooser.setItems(FXCollections.observableArrayList());
            this.history = null;
        }
    }

    public void setApiCallHistory(ApiCallHistory history) {
        assert history != null;
        setApiCallHistory(history.getHistory());
    }

    public void setApiCallHistory(ObservableList<SerializableApiCallDetails> history) {
        //only once
        if (this.history != null)
            clearApiCallHistory();

        assert history != null;
        assert apiChangeListener == null;

        this.history = history;

        apiChangeListener = change -> {
            //if first item added, select last item automatically
            //also, if item added and showNewCheckbox is selected, select last item automatically
            if (
                    (showNewCheckbox.isSelected() || logChooser.getSelectionModel().isEmpty())
                            && !LogHistoryPanel.this.history.isEmpty()
                    ) {
                Platform.runLater(() -> logChooser.getSelectionModel().selectLast());
            }
        };

        logChooser.setItems(history);
        history.addListener(apiChangeListener);

        if (!history.isEmpty())
            logChooser.getSelectionModel().selectLast();
    }

    @FXML
    public void first() {
        logChooser.getSelectionModel().selectFirst();
    }

    @FXML
    public void next() {
        logChooser.getSelectionModel().selectNext();
    }

    @FXML
    public void prev() {
        logChooser.getSelectionModel().selectPrevious();
    }

    @FXML
    public void last() {
        logChooser.getSelectionModel().selectLast();
    }

    @FXML
    public void autolast() {
        if (showNewCheckbox.isSelected())
            logChooser.getSelectionModel().selectLast();
    }

    class ApiCallDetailsCell extends ListCell<SerializableApiCallDetails> {

        public ApiCallDetailsCell() {
            super();

            this.getStylesheets().add(StyleHelper.getStyleUrl("log.css").toExternalForm());
            setPrefWidth(300);
            getStyleClass().add("select_log_label");
        }

        @Override
        public void updateItem(final SerializableApiCallDetails item, boolean empty) {
            super.updateItem(item, empty);

            if (item == null || empty) {
                setText("");
                setGraphic(null);
            } else {
                String text = item.getApiName() + " - " + item.getGeniMethodName();
                if (item.getAuthorityUrn() != null) {
                    GeniUrn authUrn = GeniUrn.parse(item.getAuthorityUrn());
                    if (authUrn == null)
                        text += " (@ \"" + item.getAuthorityUrn() + "\")";
                    else
                        text += " (@ " + authUrn.getEncodedTopLevelAuthority() + ")";
                }
                setText(text);
                boolean success = false;
                boolean busy = false;
                if (item.getGeniResponseCodeIsSuccess() != null && item.getGeniResponseCodeIsSuccess()) {
                    success = true;
                }

                //FIXME replace with codeIsBusy
                if (item.getGeniResponseCodeIsSuccess() != null && item.getGeniResponseCodeIsSuccess()) {
                    busy = true;
                }

                if (success)
                    setGraphic(GlyphUtils.createSmallGlyph(FontAwesome.Glyph.CHECK, Color.GREEN));
                else if (busy)
                    setGraphic(GlyphUtils.createSmallGlyph(FontAwesome.Glyph.TIMES, Color.GRAY));
                else
                    setGraphic(GlyphUtils.createSmallGlyph(FontAwesome.Glyph.TIMES_CIRCLE, Color.RED));

            }
        }
    }

    public void showApiCall(SerializableApiCallDetails apiCallDetails){
        assert logChooser.getItems().contains(apiCallDetails);
        setAutoShowLast(false);
        logChooser.getSelectionModel().select(apiCallDetails);
    }
}

