// Copyright 1997 The Open Group Research Institute.  All rights reserved.

package krb4.lib;

import java.io.*;
import java.util.*;

public class FileLock implements Lock {
	public static final String LOCKED_SUFFIX = ".lck";
	public static final String UNLOCKED_SUFFIX = ".ulk";
	public static final int WAITTIME_DEFAULT = 50;
	public static final int RETRY_FOREVER = 0;
	public static final int RETRY_DEFAULT = RETRY_FOREVER;
	String lockFileDirectoryName;
	String lockFileBaseName;
	File lockedFile;
	File unlockedFile;
	int waitTime;
	int retryCount;
	boolean locked;

	public FileLock(String directory, String name) throws IOException {
		this(directory, name, WAITTIME_DEFAULT, RETRY_FOREVER);
	}

	public FileLock(String directory, String name, int delay_ms,
		int retries) throws IOException {
		if (directory == null)
			lockFileDirectoryName = System.getProperty("user.dir");
		else
			lockFileDirectoryName = directory;
		lockFileBaseName = name;
		lockedFile = new File(lockFileDirectoryName,
			lockFileBaseName + LOCKED_SUFFIX);
		unlockedFile = new File(lockFileDirectoryName,
			lockFileBaseName + UNLOCKED_SUFFIX);
		waitTime = delay_ms;
		retryCount = retries;
		createLockFile();
	}

	private synchronized void createLockFile() throws IOException {
		boolean found = false;
		String lockedFileName = lockedFile.getName();
		String unlockedFileName = unlockedFile.getName();
		File d = new File(lockFileDirectoryName);
		if (!d.exists())
			d.mkdir();
		String[] files = d.list();
		for (int i = 0; i < files.length; i++) {
			if (files[i].equals(lockedFileName) || 
				files[i].equals(unlockedFileName)) {
				found = true;
				break;
			}
		}
		if (!found) {
			RandomAccessFile f = new RandomAccessFile(unlockedFile, "rw");
			f.close();
			locked = false;
		}
	}

	public synchronized void lock() throws LockException {
		int tries = 0;
		File f = new File(lockFileDirectoryName,
			lockFileBaseName + UNLOCKED_SUFFIX);
		while (!f.renameTo(lockedFile)) {
			if (retryCount == RETRY_FOREVER || tries < retryCount) {
				tries++;
				try {
					Thread.currentThread().sleep(waitTime);
				} catch (Exception e2) {}
			}
			else
				throw new LockException();
		}
		locked = true;
	}

	public synchronized void unlock() throws LockException {
		if (!locked)
			return;
		int tries = 0;
		File f = new File(lockFileDirectoryName,
			lockFileBaseName + LOCKED_SUFFIX);
		while (!f.renameTo(unlockedFile)) {
			if (retryCount == RETRY_FOREVER || tries < retryCount) {
				tries++;
				try {
					Thread.currentThread().sleep(waitTime);
				} catch (Exception e2) {}
			}
			else
				throw new LockException();
		}
		locked = false;
	}

}
