package be.iminds.ilabt.jfed.experimenter_gui.preferences.subsections;

import be.iminds.ilabt.jfed.experimenter_gui.preferences.AbstractPreferencesSubPane;
import be.iminds.ilabt.jfed.logging.BugReportAppender;
import be.iminds.ilabt.jfed.logging.JFedLoggerManager;
import be.iminds.ilabt.jfed.lowlevel.connection.SfaConnectionPool;
import be.iminds.ilabt.jfed.preferences.CorePreferenceKey;
import be.iminds.ilabt.jfed.preferences.JFedGuiPreferences;
import ch.qos.logback.classic.spi.ILoggingEvent;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ListView;
import javafx.scene.control.RadioButton;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.util.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.util.LinkedList;
import java.util.List;

/**
 * ScsPane
 */
public class LogLevelPane extends AbstractPreferencesSubPane implements BugReportAppender.LoggingEventListener {
    private final static Logger LOG = LoggerFactory.getLogger(LogLevelPane.class);

    private final JFedLoggerManager jFedLoggerManager;

    @FXML
    protected GridPane grid;

    @FXML
    protected CheckBox overwriteCheckBox;

    @FXML protected RadioButton rootDebugRadioButton;
    @FXML protected RadioButton rootInfoRadioButton;
    @FXML protected RadioButton rootWarnRadioButton;
    @FXML protected RadioButton rootErrorRadioButton;

    @FXML protected RadioButton exttermDebugRadioButton;
    @FXML protected RadioButton exttermInfoRadioButton;
    @FXML protected RadioButton exttermWarnRadioButton;
    @FXML protected RadioButton exttermErrorRadioButton;

//    @FXML protected RadioButton stdoutDebugRadioButton;
//    @FXML protected RadioButton stdoutInfoRadioButton;
//    @FXML protected RadioButton stdoutWarnRadioButton;
//    @FXML protected RadioButton stdoutErrorRadioButton;

//    @FXML protected RadioButton bugreportDebugRadioButton;
//    @FXML protected RadioButton bugreportInfoRadioButton;
//    @FXML protected RadioButton bugreportWarnRadioButton;
//    @FXML protected RadioButton bugreportErrorRadioButton;

    @FXML
    protected CheckBox cpuCheckBox;

    @FXML
    protected ListView bugreportLogList;

    protected final ObservableList<ILoggingEvent> logLines = FXCollections.observableList(new LinkedList<>());

    @FXML
    private BorderPane root;

    @Override
    public Node getRoot() {
        return root;
    }

    private final SfaConnectionPool sfaConnectionPool;
    private final JFedGuiPreferences jFedPreferences;


    @Inject
    LogLevelPane(JFedLoggerManager jFedLoggerManager, SfaConnectionPool sfaConnectionPool, JFedGuiPreferences jFedPreferences) {
        super("Logging", true);
        this.jFedLoggerManager = jFedLoggerManager;
        this.sfaConnectionPool = sfaConnectionPool;
        this.jFedPreferences = jFedPreferences;
    }

    @FXML
    private void initialize() {
        for (Node n : grid.getChildren()) {
            if (n != overwriteCheckBox)
                n.disableProperty().bind(overwriteCheckBox.selectedProperty().not());
            n.managedProperty().bind(n.visibleProperty());
        }

        overwriteCheckBox.setSelected(jFedPreferences.getBoolean(CorePreferenceKey.PREF_LOGGING_OVERWRITE, false));

        String currentSetRootLogLevel = jFedPreferences.getString(CorePreferenceKey.PREF_LOGGING_ROOT_LEVEL);
        if (currentSetRootLogLevel == null) currentSetRootLogLevel = "DEBUG";
        if (currentSetRootLogLevel.equalsIgnoreCase("DEBUG")) rootDebugRadioButton.setSelected(true);
        if (currentSetRootLogLevel.equalsIgnoreCase("INFO")) rootInfoRadioButton.setSelected(true);
        if (currentSetRootLogLevel.equalsIgnoreCase("WARN")) rootWarnRadioButton.setSelected(true);
        if (currentSetRootLogLevel.equalsIgnoreCase("ERROR")) rootErrorRadioButton.setSelected(true);

        String currentSetExttermLogLevel = jFedPreferences.getString(CorePreferenceKey.PREF_LOGGING_EXTTERM_LEVEL);
        if (currentSetExttermLogLevel == null) currentSetExttermLogLevel = "DEBUG";
        if (currentSetExttermLogLevel.equalsIgnoreCase("DEBUG")) exttermDebugRadioButton.setSelected(true);
        if (currentSetExttermLogLevel.equalsIgnoreCase("INFO")) exttermInfoRadioButton.setSelected(true);
        if (currentSetExttermLogLevel.equalsIgnoreCase("WARN")) exttermWarnRadioButton.setSelected(true);
        if (currentSetExttermLogLevel.equalsIgnoreCase("ERROR")) exttermErrorRadioButton.setSelected(true);

//        String currentSetStdoutLogLevel = jFedPreferences.getString(CorePreferenceKey.PREF_LOGGING_APPENDER_STDOUT_LEVEL);
//        if (currentSetStdoutLogLevel == null) currentSetStdoutLogLevel = "DEBUG";
//        if (currentSetStdoutLogLevel.equalsIgnoreCase("DEBUG")) stdoutDebugRadioButton.setSelected(true);
//        if (currentSetStdoutLogLevel.equalsIgnoreCase("INFO")) stdoutInfoRadioButton.setSelected(true);
//        if (currentSetStdoutLogLevel.equalsIgnoreCase("WARN")) stdoutWarnRadioButton.setSelected(true);
//        if (currentSetStdoutLogLevel.equalsIgnoreCase("ERROR")) stdoutErrorRadioButton.setSelected(true);
//
//        String currentSetBugreportLogLevel = jFedPreferences.getString(CorePreferenceKey.PREF_LOGGING_APPENDER_BUGREPORT_LEVEL);
//        if (currentSetBugreportLogLevel == null) currentSetBugreportLogLevel = "DEBUG";
//        if (currentSetBugreportLogLevel.equalsIgnoreCase("DEBUG")) bugreportDebugRadioButton.setSelected(true);
//        if (currentSetBugreportLogLevel.equalsIgnoreCase("INFO")) bugreportInfoRadioButton.setSelected(true);
//        if (currentSetBugreportLogLevel.equalsIgnoreCase("WARN")) bugreportWarnRadioButton.setSelected(true);
//        if (currentSetBugreportLogLevel.equalsIgnoreCase("ERROR")) bugreportErrorRadioButton.setSelected(true);


        cpuCheckBox.setSelected(jFedPreferences.getBoolean(CorePreferenceKey.PREF_DEBUG_CPU));

        bugreportLogList.setCellFactory(TextFieldListCell.forListView(new StringConverter<ILoggingEvent>() {
            @Override
            public String toString(ILoggingEvent e) {
                return e.getFormattedMessage();
            }

            @Override
            public ILoggingEvent fromString(String string) {
                throw new RuntimeException("not used");
            }
        }));

        BugReportAppender bugReportAppender = jFedLoggerManager.getBugReportMemoryAppender();
        if (bugReportAppender != null) {
            List<ILoggingEvent> currentLogLines = bugReportAppender.getListCopy();
            logLines.addAll(currentLogLines);
            LOG.debug("GUI is showing the BugReportAppender log lines. size=" + currentLogLines.size());
            bugReportAppender.addListeners(this);
        } else {
            LOG.warn("GUI could not get BUGREPORT appender.");
        }

        bugreportLogList.setItems(logLines);
    }

    @Override
    public void onLoggingEvent(ILoggingEvent e) {
        javafx.application.Platform.runLater(() -> {
            logLines.add(e);

            int maxSize = 512;
            if (maxSize >= 0) //so negative means infinite
                while (logLines.size() > maxSize)
                    logLines.remove(0);
        });
    }

    @FXML
    protected void testLogging() {
        save();
        jFedLoggerManager.testLogging();
    }

    private String getLogLevel(Logger logger) {
        if (logger.isTraceEnabled()) return "TRACE";
        if (logger.isDebugEnabled()) return "DEBUG";
        if (logger.isInfoEnabled()) return "INFO";
        if (logger.isWarnEnabled()) return "WARN";
        if (logger.isErrorEnabled()) return "ERROR";
        return "NONE";
    }

    private String getGuiRootLogLevel() {
        if (rootDebugRadioButton.isSelected()) return "DEBUG";
        if (rootInfoRadioButton.isSelected()) return "INFO";
        if (rootWarnRadioButton.isSelected()) return "WARN";
        if (rootErrorRadioButton.isSelected()) return "ERROR";
        LOG.warn("No log level selected by user, using default: DEBUG");
        return "DEBUG";
    }

//    private String getGuiStdoutLogLevel() {
//        if (stdoutDebugRadioButton.isSelected()) return "DEBUG";
//        if (stdoutInfoRadioButton.isSelected()) return "INFO";
//        if (stdoutWarnRadioButton.isSelected()) return "WARN";
//        if (stdoutErrorRadioButton.isSelected()) return "ERROR";
//        LOG.warn("No log level selected by user, using default: DEBUG");
//        return "DEBUG";
//    }
//
//    private String getGuiBugreportLogLevel() {
//        if (bugreportDebugRadioButton.isSelected()) return "DEBUG";
//        if (bugreportInfoRadioButton.isSelected()) return "INFO";
//        if (bugreportWarnRadioButton.isSelected()) return "WARN";
//        if (bugreportErrorRadioButton.isSelected()) return "ERROR";
//        LOG.warn("No log level selected by user, using default: DEBUG");
//        return "DEBUG";
//    }

    private String getGuiExttermLogLevel() {
        if (exttermDebugRadioButton.isSelected()) return "DEBUG";
        if (exttermInfoRadioButton.isSelected()) return "INFO";
        if (exttermWarnRadioButton.isSelected()) return "WARN";
        if (exttermErrorRadioButton.isSelected()) return "ERROR";
        LOG.warn("No log level selected by user, using default: DEBUG");
        return "DEBUG";
    }

    @Override
    public boolean check() {
        return true;
    }

    @Override
    public boolean save() {
        jFedPreferences.setBoolean(CorePreferenceKey.PREF_DEBUG_CPU, cpuCheckBox.isSelected());
        sfaConnectionPool.setDebugCpuUsage(cpuCheckBox.isSelected());

        boolean overwrite = overwriteCheckBox.isSelected();
        jFedPreferences.setBoolean(CorePreferenceKey.PREF_LOGGING_OVERWRITE, overwrite);
        if (overwrite) {
            jFedPreferences.setString(CorePreferenceKey.PREF_LOGGING_ROOT_LEVEL, getGuiRootLogLevel());
            jFedPreferences.setString(CorePreferenceKey.PREF_LOGGING_EXTTERM_LEVEL, getGuiExttermLogLevel());
//            jFedPreferences.setString(CorePreferenceKey.PREF_LOGGING_APPENDER_BUGREPORT_LEVEL, getGuiBugreportLogLevel());
//            jFedPreferences.setString(CorePreferenceKey.PREF_LOGGING_APPENDER_STDOUT_LEVEL, getGuiStdoutLogLevel());
        }

        jFedLoggerManager.updateLoggers();

        return true;
    }
}
