import org.apache.lucene.store.*;
import org.apache.lucene.store.InputStream;
import org.apache.lucene.store.OutputStream;

import java.io.*;

public class LockingFSDirectory extends Directory {

    private final Directory o_underlyingDir;
    private final File o_dir;

    /**
     * Returns the directory instance for the named location.
     */
    public static LockingFSDirectory getDirectory(String path, boolean create)
            throws IOException {
        return getDirectory(new File(path), create);
    }

    /**
     * Returns the directory instance for the named location.
     */
    public static LockingFSDirectory getDirectory(File file, boolean create)
            throws IOException {
        return new LockingFSDirectory(file, create);
    }


    private LockingFSDirectory(File p_file, boolean p_create) throws IOException {
        o_underlyingDir = FSDirectory.getDirectory(p_file, p_create);
        o_dir = new File(p_file.getCanonicalPath());
    }

    /** Returns an array of strings, one for each file in the directory. */
    public final String[] list() throws IOException {
        return o_underlyingDir.list();
    }

    /** Returns true iff a file with the given name exists. */
    public final boolean fileExists(String name) throws IOException {
        return o_underlyingDir.fileExists(name);
    }

    /** Returns the time the named file was last modified. */
    public final long fileModified(String name) throws IOException {
        return o_underlyingDir.fileModified(name);
    }

    /** Returns the time the named file was last modified. */
    public static final long fileModified(File directory, String name)
            throws IOException {
        return FSDirectory.fileModified(directory, name);
    }

    /** Returns the length in bytes of a file in the directory. */
    public final long fileLength(String name) throws IOException {
        return fileLength(name);
    }

    /** Removes an existing file in the directory. */
    public final void deleteFile(String name) throws IOException {
        o_underlyingDir.deleteFile(name);
    }

    /** Renames an existing file in the directory. */
    public final synchronized void renameFile(String from, String to)
            throws IOException {
        o_underlyingDir.renameFile(from, to);
    }

    /** Creates a new, empty file in the directory with the given name.
     Returns a stream writing this file. */
    public final OutputStream createFile(String name) throws IOException {
        return o_underlyingDir.createFile(name);
    }

    /** Returns a stream reading an existing file. */
    public final InputStream openFile(String name) throws IOException {
        return o_underlyingDir.openFile(name);
    }

    /** Construct a {@link Lock}.
     * @param name the name of the lock file
     */
    public final Lock makeLock(String name) {
        final String lockFile = new File(o_dir, name).getPath();
        return new Lock() {
            public boolean obtain() throws IOException {
                return FSLockService.getService().acquireLock(lockFile);
            }

            public void release() {
                FSLockService.getService().releaseLock(lockFile);
            }

            public String toString() {
                return "Lock@" + lockFile;
            }
        };
    }

    /** Closes the store to future operations. */
    public final synchronized void close() throws IOException {
        o_underlyingDir.close();
    }

    /** For debug output. */
    public String toString() {
        return o_underlyingDir.toString();
    }
}
