import java.io.*;

/**
 *  Sequential file of <code>double</code> items.
 *   @author  Josef.Pelikan@mff.cuni.cz
 *   @version 0.008 (2001/07/19)
 *   @since   0.007
 */
public class FileOfDouble {

    /** Memory buffer size (in 8-byte items). */
    protected static final int FILE_BUFFER = 2048;

    /** Working raw file. */
    protected RandomAccessFile f;

    /** File-name of the working file. */
    protected String fileName;

    /** Open in read-write mode. */
    protected boolean readWrite;

    /** Buffer used for <code>RandomAccessFile</code> I/O. */
    protected byte buffer[];

    /** Position of buffer start within the file (in 8-byte items). */
    protected int fPos;

    /** Number of valid buffer <strong>bytes</strong>. */
    protected int used;

    /** I/O access pointer (in 8-byte items). */
    protected int ptr;

    /** The buffer has changed (= needs to be written to disk). */
    protected boolean changed;

    protected void flushBuffer () {
        if ( changed ) {
            try {
                f.seek((long)fPos<<3);
                f.write(buffer,0,used);
                }
            catch ( IOException e ) {}
            changed = false;
            }
    }

    protected void readBuffer () {
        flushBuffer();
        fPos += ptr;
        try {
            f.seek((long)fPos<<3);
            used = f.read(buffer);
            }
        catch ( IOException e ) {
            used = 0;
            }
        ptr = 0;
    }

    public FileOfDouble ( String fn, boolean rw ) {
        readWrite = rw;
        fileName = fn;
        try {
            f = new RandomAccessFile(fileName,readWrite?"rw":"r");
            }
        catch ( FileNotFoundException e ) {
            f = null;
            }
        buffer = new byte[FILE_BUFFER<<3];
        fPos = 0;
        used = ptr = 0;
        changed = false;
    }

    public void rewrite () {
        try {
            f.seek(0L);
            if ( readWrite )
                if ( VMVersion.version() >= 1.3 ) f.setLength(0L);
                else {
                    f.close();
                    File ff = new File(fileName);
                    ff.delete();
                    f = new RandomAccessFile(fileName,"rw");
                    }
            }
        catch ( IOException e ) {}
        fPos = 0;
        used = ptr = 0;
        changed = false;
    }

    public void seek ( int pos ) {
        if ( pos < fPos || pos >= fPos + ((used+7)>>3) ) {
            flushBuffer();
            fPos = pos;
            used = ptr = 0;
            }
        else
            ptr = pos - fPos;
    }

    public int tell () {
        return( fPos + ptr );
    }

    public void put ( double d ) {
        if ( !readWrite ) return;
        if ( ptr == FILE_BUFFER ) {
            flushBuffer();
            fPos += FILE_BUFFER;
            used = ptr = 0;
            }
        long dLong = Double.doubleToLongBits(d);
        int bPtr = ptr++ << 3;
        buffer[bPtr++] = (byte)(dLong      );
        buffer[bPtr++] = (byte)(dLong >>= 8);
        buffer[bPtr++] = (byte)(dLong >>= 8);
        buffer[bPtr++] = (byte)(dLong >>= 8);
        buffer[bPtr++] = (byte)(dLong >>= 8);
        buffer[bPtr++] = (byte)(dLong >>= 8);
        buffer[bPtr++] = (byte)(dLong >>= 8);
        buffer[bPtr  ] = (byte)(dLong >>  8);
        if ( (ptr << 3) > used ) used = (ptr << 3);
        changed = true;
    }

    public double get () {
        if ( (ptr << 3) + 8 > used ) readBuffer();
        if ( used < 8 ) return -1.0;
        int bPtr = ptr++ << 3;
        long dLong = (((long)buffer[bPtr  ]      ) & 0x00000000000000FFL) +
                     (((long)buffer[bPtr+1] <<  8) & 0x000000000000FF00L) +
                     (((long)buffer[bPtr+2] << 16) & 0x0000000000FF0000L) +
                     (((long)buffer[bPtr+3] << 24) & 0x00000000FF000000L) +
                     (((long)buffer[bPtr+4] << 32) & 0x000000FF00000000L) +
                     (((long)buffer[bPtr+5] << 40) & 0x0000FF0000000000L) +
                     (((long)buffer[bPtr+6] << 48) & 0x00FF000000000000L) +
                      ((long)buffer[bPtr+7] << 56);
        return Double.longBitsToDouble(dLong);
    }

    public void close () {
        if ( f != null ) {
            flushBuffer();
            try {
                f.close();
                }
            catch ( IOException e ) {}
            f = null;
            }
        fPos = used = ptr = 0;
    }

}
