package com.interpress_project.modernshare.client.controller.model;

import java.io.File;
import java.io.FileFilter;

import org.apache.commons.io.FilenameUtils;

import com.interpress_project.modernshare.client.controller.command.TaskManager;
import com.interpress_project.modernshare.ipcommon.SystemBase;
import com.jniwrapper.win32.io.FileSystemEvent;
import com.jniwrapper.win32.io.FileSystemEventListener;
import com.jniwrapper.win32.io.FileSystemException;
import com.jniwrapper.win32.io.FileSystemWatcher;

/**
 * @stereotype Singleton factory
 */
public class FsWatcherManager {
	private SystemBase sb = SystemBase.getInstance();
	private FileSystemWatcher watcher = null;
	private TaskManager taskmgr = TaskManager.getInstance();
	private FsEventListener listener = null;
	private String rootpath = null;

	/**
	 * FsWatcherManager
	 * @param path
	 */
	public FsWatcherManager(String rootpath) {
		sb.getLogger().debug(rootpath + " is registered as watcher point.");

		this.rootpath = rootpath;
		this.watcher = new FileSystemWatcher(rootpath, new OmitFileFilter(), true);
		this.listener = new FsEventListener();
		FileSystemWatcher.WatcherOptions options = this.watcher.getOptions();
		options.setNotifyChangeAttributes(false);
		options.setNotifyChangeDirName(true);
		options.setNotifyChangeFileName(true);
		options.setNotifyChangeSize(true);
		options.setNotifyLastAccess(false);
		options.setNotifyLastModified(false);
	}

	/**
	 * addFileSystemListener
	 * @param listener
	 */
	public void addFileSystemListener(FileSystemEventListener listener) {
		watcher.addFileSystemListener(listener);
	}

	/**
	 * removeFileSystemListener
	 * @param listener
	 */
	public void removeFileSystemListener(FileSystemEventListener listener) {
		watcher.removeFileSystemListener(listener);
	}

	/**
	 * start
	 */
	public void start() {
		if (watcher.isWatching()) {
			watcher.stop();
			watcher.removeFileSystemListener(listener);
		}
		watcher.addFileSystemListener(listener);
		try {
			watcher.start();
		}
		catch (FileSystemException ex) {
			sb.getLogger().error("FsWatcherManager for " + rootpath + " failed.");
			return;
		}
		sb.getLogger().debug("FsWatcherManager for " + rootpath + " started.");
	}

	/**
	 * stop
	 */
	public void stop() {
		if (watcher.isWatching()) {
			watcher.stop();
		}
		watcher.removeFileSystemListener(listener);
		sb.getLogger().debug("FsWatcherManager for " + rootpath + " stopped.");
	}

	/**
	 * dispose
	 */
	public void dispose() {
		stop();
		watcher = null;
		sb.getLogger().debug("FsWatcherManager for " + rootpath + " disposed.");
	}

	/**
	 * FsEventListener 
	 * @author ys
	 */
	private class FsEventListener implements FileSystemEventListener {
		/**
		 * handle
		 */
		public void handle(FileSystemEvent event) {
			String fname = event.getFileInfo().getFileName();
			taskmgr.updateSchedule(fname);
		}
	}

	/**
	 * OmitFileFilter
	 * @author ys
	 */
	private class OmitFileFilter implements FileFilter {
		private PropertyManager propmgr = PropertyManager.getInstance();
		private String[] filters;

		/**
		 * OmitFileFilter
		 */
		public OmitFileFilter() {
			filters = propmgr.getIgnoreFilterList();
		}

		/**
		 * accept
		 */
		public boolean accept(File pathname) {
			String path = pathname.getAbsolutePath();
			String name = FilenameUtils.getName(path);

			// Path includes .svn folder.
			if (FilenameUtils.wildcardMatchOnSystem(path, "*\\.svn\\*")) {
				return false;
			}

			// Path includes svn ignore filter.
			for (int i = 0; i < filters.length; i++) {
				if (FilenameUtils.wildcardMatchOnSystem(name, filters[i])) {
					return false;
				}
			}
			return true;
		}
	}
}
