/*
 *                 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.reservedcheckout;

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

import org.netbeans.lib.cvsclient.*;
import org.netbeans.lib.cvsclient.command.*;
import org.netbeans.lib.cvsclient.event.*;
import org.netbeans.lib.cvsclient.file.*;
import org.netbeans.lib.cvsclient.progress.*;
import org.netbeans.lib.cvsclient.progress.sending.*;

/**
 * @author Thomas Singer
 */
public final class EditCommand extends AbstractCommand {

	// Static =================================================================

	public static EditCommand createInstance(FsDirectoryPath fsDirectory) {
		return new EditCommand(Collections.singleton(fsDirectory));
	}

	public static EditCommand createInstance(Collection<FsFilePath> fsFiles) {
		return new EditCommand(fsFiles);
	}

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

	private final Collection<? extends FsPath> fsPaths;
	private boolean recursive = true;
	private boolean checkThatUnedited;
	private boolean forceEvenIfEdited;
	private Watch temporaryWatch;

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

	private EditCommand(Collection<? extends FsPath> fsPaths) {
		this.fsPaths = fsPaths;
	}

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

	@Override
	public boolean execute(IRequestProcessor requestProcessor, IEventSender eventSender, ICvsListenerRegistry listenerRegistry, IClientEnvironment clientEnvironment, IProgressViewer progressViewer) throws CommandException {
		final Set<String> cvsRcOptions = requestProcessor.parseCvsRcFile("edit", clientEnvironment);
		final boolean serverCheckThatUnedited = cvsRcOptions.contains("-c");

		final ICvsFiles cvsFiles;
		try {
			cvsFiles = FileSystemScanner.scan(fsPaths, recursive, clientEnvironment);
		}
		catch (IOException ex) {
			throw new IOCommandException(ex);
		}

		if (serverCheckThatUnedited) {
			checkThatUnedited = true;
		}

		if (checkThatUnedited) {
			final IProgressViewer editorsProgressViewer = new RangeProgressViewer(progressViewer, 0.0, 0.5);
			final IRequestsProgressHandler requestsProgressHandler = new FileStateRequestsProgressHandler(new RangeProgressViewer(editorsProgressViewer, 0.0, 0.5), cvsFiles);

			final EditEditorsMessageParser parser = new EditEditorsMessageParser(clientEnvironment.getCvsRoot().getUser());
			parser.registerListeners(listenerRegistry);
			try {
				requestProcessor.communicateWithServer(new EditorsRequestFactory(cvsFiles, fsPaths),
				                                       requestsProgressHandler, clientEnvironment, getGlobalOptions());
			}
			finally {
				parser.unregisterListeners(listenerRegistry);
			}

			if (parser.isFilesEdited()) {
				eventSender.notifyMessageListeners("Cannot edit files, because they already are edited!", true, false);
				return false;
			}

			progressViewer = new RangeProgressViewer(progressViewer, 0.5, 1.0);
		}

		final IRequestsProgressHandler requestsProgressHandler = new FileStateRequestsProgressHandler(new RangeProgressViewer(progressViewer, 0.0, 0.5), cvsFiles);
		return requestProcessor.communicateWithServer(new EditRequestFactory(cvsFiles, checkThatUnedited, forceEvenIfEdited, temporaryWatch),
		                                              requestsProgressHandler, clientEnvironment, getGlobalOptions());
	}

	@Override
	public String getCvsCommandLine() {
		final StringBuilder cvsCommandLine = new StringBuilder("edit ");
		if (!recursive) {
			cvsCommandLine.append("-l ");
		}
		CommandUtils.appendFileArguments(fsPaths, cvsCommandLine);
		return cvsCommandLine.toString();
	}

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

	/**
	 * Sets whether to check for unedited files.
	 * This is cvs' -c option.
	 */
	public void setCheckThatUnedited(boolean checkThatUnedited) {
		this.checkThatUnedited = checkThatUnedited;
	}

	/**
	 * Sets whether the edit is forces even if the files are edited.
	 * This is cvs' -f option.
	 */
	public void setForceEvenIfEdited(boolean forceEvenIfEdited) {
		this.forceEvenIfEdited = forceEvenIfEdited;
	}

	/**
	 * Sets the temporary watch.
	 * This is cvs' -a option.
	 */
	public void setTemporaryWatch(Watch temporaryWatch) {
		this.temporaryWatch = temporaryWatch;
	}

}
