package org.bdware.sc.boundry.utils;

import com.google.gson.JsonObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bdware.sc.ContractProcess;
import org.bdware.sc.compiler.PermissionStub;
import org.bdware.sc.db.MultiIndexTimeRocksDBUtil;
import org.bdware.sc.node.Permission;
import org.rocksdb.RocksDB;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@PermissionStub(permission = Permission.MultiTagIndexDB)
public class MultiTagIndexDBUtil {
    private static final Logger LOGGER = LogManager.getLogger(MultiIndexTimeRocksDBUtil.class);

    static Map<String, MultiTagIndexDBUtil> cacheDB = new HashMap<>();

    static {
        RocksDB.loadLibrary();
    }

    MultiIndexTimeRocksDBUtil rocksDB;
    String path;

    public MultiTagIndexDBUtil(String path, String tableName) {
        try {
            this.path = path;
            File parent = new File("./ContractDB/" + ContractProcess.getContractDir());
            File dir = new File(parent, path);

            LOGGER.info("init RocksDB in " + dir.getAbsolutePath());
            if (!dir.exists()) {
                LOGGER.trace("create directory " + dir.getAbsolutePath() + ": " + dir.mkdirs());
            }
            File lockFile = new File(dir, "LOCK");
            LOGGER.trace("delete file" + lockFile.getAbsolutePath() + ": " + lockFile.delete());
            rocksDB = new MultiIndexTimeRocksDBUtil(dir.getAbsolutePath(), tableName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static MultiTagIndexDBUtil loadDB(String path, String tableName) {
        if (cacheDB.containsKey(path)) {
            return cacheDB.get(path);
        }
        MultiTagIndexDBUtil ret = new MultiTagIndexDBUtil(path, tableName);
        cacheDB.put(path, ret);
        return ret;
    }

    public void close() {
        rocksDB.close();
        cacheDB.remove(path);
    }

    public String get(String key) {
        try {
            return new String(rocksDB.get(key));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public long size() {
        try {
            return rocksDB.size();
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    public void put(String label, String value) {
        try {
            rocksDB.put(label, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public List<String> getTags(String prefix) {
        return rocksDB.getIndexStartWith(prefix);
    }

    public List<String> getAllTags() {
        List<String> list = rocksDB.getAllIndexKey();
        return list;
    }

    public long getSize(String tag) {
        try {
            return rocksDB.size(tag);
        } catch (Exception e) {
            e.printStackTrace();

        }
        return 0L;
    }

    public long queryOffset(String tag, long startTimestamp) {
        return rocksDB.queryOffset(tag, startTimestamp);
    }

    public List<JsonObject> queryByOffset(String tag, long offset, int count) {
        return rocksDB.queryByOffset(tag, offset, count);
    }

    public List<Long> countInInterval(String tag, long startTime, long endTime, long interval) {
        List<Long> ret = new ArrayList<>();
        if (interval <= 0) return ret;
        long start = rocksDB.queryOffset(tag, startTime);
        long delta;
        startTime += interval;
        for (; startTime < endTime; startTime += interval) {
            delta = rocksDB.queryOffset(tag, startTime);
            ret.add(delta - start);
            start = delta;
        }
        delta = rocksDB.queryOffset(tag, endTime);
        ret.add(delta - start);
        return ret;
    }

    public List<String> queryInInterval(String tag, long startTime, long endTime) {
        return rocksDB.queryByDateAsString(tag, startTime, endTime);
    }
}
