/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Contributors:  Mathias Bogaert
package org.apache.log4j.helpers;

import java.io.File;
import java.net.URL;

/**
 Check every now and then that a certain file has not changed. If it
 has, then call the {@link #doOnChange} method.


 @author Ceki G&uuml;lc&uuml;
 @since version 0.9.1 */
public abstract class FileWatchdog extends Thread {

	/**
	 The default delay between every file modification check, set to 60
	 seconds.  */
	static final public long DEFAULT_DELAY = 60000;
	/**
	 The name of the file to observe  for changes.
	 */
	protected String filename;

	/**
	 The delay to observe between every check. By default set {@link
	 #DEFAULT_DELAY}. */
	protected long delay = DEFAULT_DELAY;

	File file;
	long lastModif = 0;
	boolean warnedAlready = false;
	boolean interrupted = false;

	protected FileWatchdog(String filename) {
		this.filename = filename;
		file = new File(filename);
		if (!file.exists()) {
			file = getFileFromClasspath(filename);
		}
		setDaemon(true);
		checkAndConfigure();
	}

	private File getFileFromClasspath(String searchName) {
		ClassLoader cl = this.getClass().getClassLoader();
		URL url = null;
		do {
			url = cl.getResource(searchName);
			cl = cl.getParent();
		} while (url == null && cl != null);
		filename = url.getFile();
		filename = filename.replaceAll("%20", " ");
		return new File(filename);
	}

	/**
	 Set the delay to observe between each check of the file changes.
	 */
	public void setDelay(long delay) {
		this.delay = delay;
	}

	abstract protected void doOnChange();

	protected void checkAndConfigure() {
		boolean fileExists;
		try {
			fileExists = file.exists();
		} catch (SecurityException e) {
			LogLog.warn("Was not allowed to read check file existance, file:[" + filename + "].");
			interrupted = true; // there is no point in continuing
			return;
		}

		if (fileExists) {
			long l = file.lastModified(); // this can also throw a SecurityException
			if (l > lastModif) { // however, if we reached this point this
				lastModif = l; // is very unlikely.
				doOnChange();
				warnedAlready = false;
			}
		} else {
			if (!warnedAlready) {
				LogLog.debug("[" + filename + "] does not exist.");
				warnedAlready = true;
			}
		}
	}

	public void run() {
		while (!interrupted) {
			try {
				Thread.sleep(delay);
			} catch (InterruptedException e) {
				// no interruption expected
			}
			checkAndConfigure();
		}
	}
}

