package anastore.client;

import anastore.store.NoSuchDatum;
import anastore.store.VersionStore;
import anastore.util.BlockData;
import anastore.util.BoundSet;
import anastore.util.Bug;
import anastore.util.ProtocolViolationException;

import java.nio.ByteBuffer;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * A read-only snapshot.  Read-only snapshots cannot abort.  Note that
 * it is still necessary to commit read-only transactions in order to
 * free up resources.
 */
public class ROSnapshot extends Snapshot
{
    private final VersionStore<BlockData> _cache;
    private final long _timestamp;
    private final BoundSet _boundSet;

    private boolean _committed = false;

    ROSnapshot(VersionStore<BlockData> cache, long timestamp,
               BoundSet boundSet)
    {
        _cache = cache;
        _timestamp = timestamp;
        _boundSet = boundSet;
        _boundSet.add(timestamp);
    }

    @Override
    public void finalize()
    {
        if (!_committed) {
            System.err.println("Warning: ROSnapshot not committed");
            _boundSet.remove(_timestamp);
        }
    }

    /**
     * Retrieves a read-only copy of the requested block from the
     * current snapshot.
     *
     * @throws IllegalStateException if the transaction has been
     * committed
     * @throws NoSuchDatum if id refers to a datum that does not exist
     * in the current snapshot
     */
    public synchronized ByteBuffer readBlock(long id)
        throws NoSuchDatum, IllegalStateException
    {
        if (_committed)
            throw new IllegalStateException("Transaction committed");
        try {
            return _cache.get(id, _timestamp).get().toROByteBuffer();
        } catch (IOException e) {
            throw new ProtocolViolationException(e);
        }
    }

    /**
     * Commit the current transaction, allowing its resources to be
     * freed.
     *
     * @throws IllegalStateException if the transaction has already
     * been committed
     */
    public synchronized void commit()
        throws IllegalStateException
    {
        _boundSet.remove(_timestamp);
        _committed = true;
    }

    @Override
    public String toString()
    {
        return "ROSnapshot<" + Integer.toHexString(hashCode()) + "@" +
            _timestamp + ">";
    }
}
