package eu.eudat.core.logger.common;

import org.json.JSONObject;
import org.springframework.core.env.Environment;
import types.LoggingOutputType;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created by ikalyvas on 5/30/2018.
 */
public abstract class AbstractBatchLogger {
    private Map<String, Object> concurrentHashMap = new ConcurrentHashMap<String, Object>();

    public AbstractBatchLogger(Environment environment) {
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

        executor.scheduleAtFixedRate(() -> this.outputData(), Long.parseLong(environment.getProperty("http-logger.initial-delay")), Long.parseLong(environment.getProperty("http-logger.delay")), TimeUnit.SECONDS);
    }

    public abstract LoggingOutputType logOutputType();

    public <T> void put(String key, T data) {
        this.concurrentHashMap.put(key, data);
    }

    public void clear() {
        this.concurrentHashMap.clear();
    }

    private Map<String, Object> getAndClear() {
        Map<String, Object> map = new HashMap<>();
        map.putAll(this.concurrentHashMap);
        this.concurrentHashMap.keySet().removeAll(map.keySet());
        return map;
    }

    public String tranformLog() {
        if (this.concurrentHashMap.size() > 0) {
            Map<String, Collection<Object>> transformedMap = new HashMap<>();
            transformedMap.put("entries", this.getAndClear().values());
            if (this.logOutputType().equals(LoggingOutputType.JSON))
                return new JSONObject(transformedMap).toString();
            if (this.logOutputType().equals(LoggingOutputType.FILE))
                return transformedMap.toString(); //TODO actual implementation of file Logger
            else throw new RuntimeException("Unsupported LoggingOutputType type");
        } else return null;
    }

    public abstract void outputData();
}
