/*
 *                 Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 *
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.lib.cvsclient.command;

import java.io.*;
import java.util.*;

import org.netbeans.lib.cvsclient.*;
import org.netbeans.lib.cvsclient.admin.*;
import org.netbeans.lib.cvsclient.event.*;
import org.netbeans.lib.cvsclient.file.*;
import org.netbeans.lib.cvsclient.util.*;

/**
 * @author Thomas Singer
 */
public final class DirectoryPruner
		implements ICvsListener, IDirectoryListener {

	// Fields =================================================================

	private final List<FsDirectoryPath> directoriesToScan = new ArrayList<FsDirectoryPath>();
	private final IClientEnvironment clientEnvironment;

	// Setup ==================================================================

	public DirectoryPruner(IClientEnvironment clientEnvironment) {
		BugLog.assertNotNull(clientEnvironment);

		this.clientEnvironment = clientEnvironment;
	}

	// Implemented ============================================================

	public void processingDirectory(FsDirectoryPath fsDirectory) {
		if (FsPathUtils.isRoot(fsDirectory)) {
			return;
		}

		if (directoriesToScan.contains(fsDirectory)) {
			return;
		}

		directoriesToScan.add(fsDirectory);
	}

	public void registerListeners(ICvsListenerRegistry listenerRegistry) {
		listenerRegistry.addDirectoryListener(this);
	}

	public void unregisterListeners(ICvsListenerRegistry listenerRegistry) {
		listenerRegistry.removeDirectoryListener(this);
	}

	// Accessing ==============================================================

	/**
	 * Remove any directories that don't contain any files
	 */
	public void pruneEmptyDirectories() throws IOException {
		while (directoriesToScan.size() > 0) {
			final FsDirectoryPath fsDirectory = directoriesToScan.remove(0);
			pruneEmptyDirectory(fsDirectory);
		}
	}

	// Utils ==================================================================

	private boolean pruneEmptyDirectory(FsDirectoryPath fsDirectory) throws IOException {
		final ILocalFileReader localFileReader = clientEnvironment.getLocalFileReader();
		final IAdminWriter adminWriter = clientEnvironment.getAdminWriter();
		final IAdminReader adminReader = clientEnvironment.getAdminReader();

		directoriesToScan.remove(fsDirectory);

		if (!localFileReader.exists(fsDirectory)) {
			return true;
		}

		final List<String> fileNames = new ArrayList<String>();
		final List<String> directoryNames = new ArrayList<String>();
		localFileReader.listFilesAndDirectories(fsDirectory, fileNames, directoryNames);

		if (fileNames.size() > 0) {
			return false;
		}

		if (hasFileEntry(fsDirectory, adminReader)) {
			return false;
		}

		for (final String directoryName : directoryNames) {
			if (!pruneEmptyDirectory(FsDirectoryPath.createRelativeInstance(fsDirectory, directoryName))) {
				return false;
			}
		}

		if (adminReader.hasCvsDirectory(fsDirectory)) {
			try {
				adminWriter.removeEntryForFile(fsDirectory);
			}
			catch (FileNotFoundException ex) {
				// ignore
				return false;
			}

			adminWriter.pruneDirectory(fsDirectory);
			return true;
		}

		return false;
	}

	private boolean hasFileEntry(FsDirectoryPath fsDirectory, IAdminReader adminReader) throws IOException {
		for (final Entry entry : adminReader.getEntries(fsDirectory)) {
			if (!entry.isDirectory()) {
				return true;
			}
		}
		return false;
	}
}
