package be.iminds.ilabt.jfed.log.cache;

import be.iminds.ilabt.jfed.call_log_output.SerializableApiCallDetails;
import be.iminds.ilabt.jfed.log.ApiCallDetails;
import be.iminds.ilabt.jfed.log.Logger;
import be.iminds.ilabt.jfed.log.ResultListener;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.transformation.TransformationList;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.*;

/**
 * AllApiCallsList all API calls holds a list of all API calls ever done. This includes calls done outside of the Task system.
 * It is uses the ApiCallDetailsCache to make this lightweight.
 */
@Singleton
public class AllApiCallsList implements ResultListener {
    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(AllApiCallsList.class);

    private final ObservableList<ApiCallDetailsRef> allCalls;
    private final Logger logger;
    private final ApiCallDetailsCache cache;

    @Inject
    public AllApiCallsList(Logger logger, ApiCallDetailsCache cache) {
        this.logger = logger;
        this.cache = cache;
        this.allCalls = FXCollections.observableArrayList();

        this.logger.addResultListener(this);
    }

    @Override
    public void onResult(ApiCallDetails result) {
        try {
            ApiCallDetailsRef ref = cache.registerApiCallDetails(result);
            synchronized (allCalls) {
                Platform.runLater(() -> allCalls.add(ref));
            }
        } catch (Exception e) {
            LOG.error("AllApiCallsList failed to log a call", e);
        }
    }

    public List<ApiCallDetailsRef> getCalls() {
        //return current copy to prevent concurrency issues and prevent caller from editing
        synchronized (allCalls) {
            return new ArrayList<>(allCalls);
        }
    }

    /**
     * only use on FX thread
     * @return
     */
    public ObservableList<ApiCallDetailsRef> getObservableCalls() {
        return FXCollections.unmodifiableObservableList(allCalls);
    }
    public ObservableList<SerializableApiCallDetails> getObservablSerializableCalls() {
        return new TransformationList<SerializableApiCallDetails, ApiCallDetailsRef>(allCalls) {
            @Override
            public int size() {
                return getSource().size();
            }

            @Override
            public SerializableApiCallDetails get(int index) {
                return cache.getFullApiDetails(getSource().get(index));
            }

            @Override
            protected void sourceChanged(ListChangeListener.Change<? extends ApiCallDetailsRef> c) {
                //don't think I need to do something here
            }

            @Override
            public int getSourceIndex(int index) {
                return index;
            }
        };
    }

    public ApiCallDetailsCache getCache() {
        return cache;
    }
}
