package org.limewire.nio.channel;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import org.limewire.collection.Buffer;
import org.limewire.nio.observer.WriteObserver;
import org.limewire.util.ByteUtils;

/** A simple writer that maintains statistics about how much was written. */
public class StatisticGatheringWriter extends AbstractChannelInterestWriter {

    private final static long NANO_START = System.nanoTime();
    private static final int HISTORY = 50;

    private final Buffer<Long> handleWrites = new Buffer<Long>(HISTORY);
    private final Buffer<Long> interestWrites = new Buffer<Long>(HISTORY);
    private final Buffer<Boolean> interestWritesStatus = new Buffer<Boolean>(HISTORY);
    private final Buffer<Long> writeTimes = new Buffer<Long>(HISTORY);
    private final Buffer<Long> writeAmounts = new Buffer<Long>(HISTORY);
    private final long msStart = System.currentTimeMillis();
    
    private long amountWrote, totalHandleWrite, totalInterestWrite, positiveInterestWrite;
    
    @Override
    public int write(ByteBuffer src) throws IOException {
        writeTimes.add(System.nanoTime() - NANO_START);
        int wrote = super.write(src);
        amountWrote += wrote;
        writeAmounts.add((long)wrote);
        return wrote;
    }
    
    @Override
    public boolean handleWrite() throws IOException {
        handleWrites.add(System.nanoTime() - NANO_START);
        totalHandleWrite++;
        return super.handleWrite();
    }

    @Override
    public void interestWrite(WriteObserver observer, boolean status) {
        interestWrites.add(System.nanoTime() - NANO_START);
        interestWritesStatus.add(status);
        totalInterestWrite++;
        if (status)
            positiveInterestWrite++;
        super.interestWrite(observer, status);
    }
    
    public Object inspect() {
        Map<String,Object> ret = new HashMap<String,Object>();
        ret.put("ver",1);
        ret.put("ms",msStart);
        ret.put("hw",getPacked(handleWrites));
        ret.put("iw",getPacked(interestWrites));
        ret.put("iws", getPackedBool(interestWritesStatus));
        ret.put("wt",getPacked(writeTimes));
        ret.put("wa",getPacked(writeAmounts));
        ret.put("totalWrote", amountWrote);
        ret.put("totalHW", totalHandleWrite);
        ret.put("totalIW", totalInterestWrite);
        ret.put("totalIWP", positiveInterestWrite);
        return ret;
    }
    
    private byte [] getPacked(Buffer<Long> b) {
        byte [] ret = new byte[b.getSize() * 8];
        for (int i = 0; i < b.getSize(); i++)
            ByteUtils.long2beb(b.get(i), ret, i*8);
        return ret;
    }
    
    private byte [] getPackedBool(Buffer<Boolean> b) {
        byte [] ret = new byte[b.getSize()];
        for (int i = 0; i < b.getSize(); i++)
            ret[i] = (byte)(b.get(i) ? 1 : 0);
        return ret;
    }

}
