package org.bdware.sc.index;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;

public class LenVarTimeSerialIndex {
    private static final Logger LOGGER = LogManager.getLogger(LenVarTimeSerialIndex.class);
    //    static int chunckSize = 10240;
//    public String fileDir;
//    File currentFile;
    RandomAccessFile file;
    int dataSize = 20;
    long fileSize = 0;
    byte[] dateBuff = new byte[8];

    public LenVarTimeSerialIndex(String fileName, int dataSize) {
        try {
            File f = new File(fileName);
            File parent = f.getParentFile();
            if (!parent.exists()) {
                LOGGER.trace("create directory " + parent.getAbsolutePath() + ": " + parent.mkdirs());
            }
            if (!f.exists()) {
                LOGGER.trace("create file " + f.getAbsolutePath() + ": " + f.createNewFile());
            }
            file = new RandomAccessFile(f, "rw");
            this.dataSize = dataSize;
            fileSize = file.length() / (dataSize + 8L);
            this.file.seek(fileSize * (dataSize + 8L));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void finalize() {
        try {
            file.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public synchronized void seek(int pos) {
        try {
            file.seek(pos);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public synchronized void manullyIndex(long date, byte[] hash) {
        try {
            checkData(hash);
            fileSize++;
            for (int i = 0; i < 8; i++) {
                dateBuff[i] = (byte) ((date >> (56 - i * 8)) & 0xFF);
            }
            file.write(dateBuff);
            file.write(hash);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void checkData(byte[] hash) {
        if (hash == null || hash.length != dataSize)
            throw new IllegalArgumentException("unsupported data size:" +
                    (null == hash ? "null" : hash.length));
    }

    public synchronized long index(byte[] hash) {
        long ret = 0;
        try {
            checkData(hash);
            fileSize++;
            ret = System.currentTimeMillis();
            for (int i = 0; i < 8; i++) {
                dateBuff[i] = (byte) ((ret >> (56 - i * 8)) & 0xFF);
            }
            file.write(dateBuff);
            file.write(hash);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ret;
    }

    public synchronized List<byte[]> request(long offset, int len) {
        List<byte[]> ret = new ArrayList<>();
        if (offset < 0) {
            offset = 0;
        }
        if (offset < fileSize) {
            long pos = 0;
            try {
                pos = file.getFilePointer();
                file.seek(offset * (dataSize + 8L));
                for (; offset < fileSize && len > 0; len--) {
                    byte[] data = new byte[dataSize + 8];
                    file.read(data);
                    ret.add(data);
                    offset++;
                }
                file.seek(pos);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    file.seek(pos);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return ret;
        } else
            return new ArrayList<>();
    }

    public long size() {
        return fileSize;
    }

    public synchronized List<byte[]> requestLast(int count) {
        long offset = fileSize - count;
        return request(offset, count);
    }
}
