package org.bdware.sc.index;

import org.bdware.sc.util.HashUtil;

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

public class LenVarTimeSerialIndex2 {
    static int chunckSize = 10240;
    public String fileDir;
    public int dataSize = 20;
    public long fileSize = 0;
    File currentFile;
    RandomAccessFile file;
    byte[] dateBuff = new byte[8];

    public LenVarTimeSerialIndex2(String fileName) {
        File f2 = new File(fileName + ".datasize");
        if (!f2.exists())
            throw new IllegalArgumentException("index file don't exists");
        try {
            File f = new File(fileName);

            if (!f.exists()) {
                f.createNewFile();
            }
            file = new RandomAccessFile(fileName, "rw");
            this.dataSize = (int) f2.length();
            fileSize = file.length() / (dataSize + 8L);
            this.file.seek(fileSize * (dataSize + 8L));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static long toDate(byte[] buff) {
        long ret = 0;
        for (int i = 0; i < 8; i++) {
            ret <<= 8;
            ret |= (buff[i] & 0xFF);
        }
        return ret;
    }

    @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) {
            e.printStackTrace();
        }
    }

    public synchronized void manullyIndex(long date, byte[] hash) {
        try {
            if (hash == null || hash.length != dataSize)
                throw new IllegalArgumentException("unsupported data size:" + hash.length);
            fileSize++;
            for (int i = 0; i < 8; i++)
                dateBuff[i] = (byte) ((date >> (56 - i * 8)) & 0xFF);
            file.seek(file.length());
            file.write(dateBuff);
            file.write(hash);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public synchronized long index(byte[] hash) {
        long ret = 0;
        try {
            if (hash == null || hash.length != dataSize)
                throw new IllegalArgumentException("unsupported data size:" + hash.length);
            fileSize++;
            ret = System.currentTimeMillis();
            for (int i = 0; i < 8; i++)
                dateBuff[i] = (byte) ((ret >> (56 - i * 8)) & 0xFF);
            file.seek(file.length());
            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<byte[]>();
        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<byte[]>();
    }

    public long size() {
        return fileSize;
    }

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

    public synchronized List<byte[]> requestByTime(long startTime, long endTime) {
        long start = bsearch(0, fileSize, startTime);
        long end = bsearch(0, fileSize, endTime);
        return request(start, (int) (end - start + 1));
    }

    private long bsearch(long s, long e, long time) {
        // TODO 这个bsearch一看就有毒，楚天你可以改它。
        if (e <= s + 1)
            return s;
        long offset = (s + e) / 2;
        try {
            file.seek(offset * (dataSize + 8L));
            file.read(dateBuff);
            long date = HashUtil.bytes2Long(dateBuff);
            if (date < time)
                return bsearch(offset + 1, e, time);
            else
                return bsearch(s, offset, time);
        } catch (IOException e1) {
            e1.printStackTrace();
            return -1;
        }

    }
}
