package org.netbeans.lib.cvsclient.response;

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

import org.netbeans.lib.cvsclient.*;
import org.netbeans.lib.cvsclient.io.*;
import org.netbeans.lib.cvsclient.util.*;

/**
 * @author Thomas Singer
 */
public final class ResponseParser {

	// Constants ==============================================================

	private static final ILogger LOG = LoggerManager.getLogger("javacvs.responseparser");

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

	private final IResponseHandler responseProcessor;

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

	public ResponseParser(IResponseHandler responseProcessor) {
		BugLog.assertNotNull(responseProcessor);

		this.responseProcessor = responseProcessor;
	}

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

	public Boolean processResponse(String responseName, IConnectionStreams connectionStreams) throws IOException {
		if (responseName.equalsIgnoreCase("E")) {
			final String line = StreamUtilities.readLine(connectionStreams.getLoggedReader());
			responseProcessor.processErrorMessageResponse(line);
			return null;
		}
		else if (responseName.equalsIgnoreCase("M")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String line = StreamUtilities.readLine(reader);
			responseProcessor.processMessageResponse(line);
			return null;
		}
		else if (responseName.equalsIgnoreCase("MT")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String text = StreamUtilities.readLine(reader);
			responseProcessor.processMessageTaggedResponse(text);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Updated")) {
			final Reader reader = connectionStreams.getLoggedReader();
			// Updated build/
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			// /misc/repository/smartcvs/build/changelog.txt
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			// /changelog.txt/1.61//-ko/
			final String entryLine = StreamUtilities.readLine(reader);
			// u=rw,g=rw,o=rw
			final String mode = StreamUtilities.readLine(reader);
			// 1895
			final String fileLengthString = StreamUtilities.readLine(reader);

			final int fileLength;
			try {
				fileLength = Integer.parseInt(fileLengthString);
				responseProcessor.processUpdatedResponse(relativeLocalDirectory, repositoryFilePath, entryLine, mode, fileLength, connectionStreams);
			}
			catch (NumberFormatException ex) {
				// ignore
			}
			return null;
		}
		else if (responseName.equalsIgnoreCase("Merged")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			final String entryLine = StreamUtilities.readLine(reader);
			final String mode = StreamUtilities.readLine(reader);
			final String fileLengthString = StreamUtilities.readLine(reader);

			final int fileLength;
			try {
				fileLength = Integer.parseInt(fileLengthString);
				responseProcessor.processMergedResponse(relativeLocalDirectory, repositoryFilePath, entryLine, mode, fileLength, connectionStreams);
			}
			catch (NumberFormatException ex) {
				// ignore
			}
			return null;
		}
		else if (responseName.equalsIgnoreCase("Checked-in")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			final String entryLine = StreamUtilities.readLine(reader);
			responseProcessor.processCheckedInResponse(relativeLocalDirectory, repositoryFilePath, entryLine);
			return null;
		}
		else if (responseName.equalsIgnoreCase("New-entry")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			final String entryLine = StreamUtilities.readLine(reader);
			responseProcessor.processNewEntryResponse(relativeLocalDirectory, repositoryFilePath, entryLine);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Set-static-directory")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			responseProcessor.processSetStaticDirectoryResponse(relativeLocalDirectory, repositoryFilePath);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Clear-static-directory")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryDirectoryPath = StreamUtilities.readLine(reader);
			responseProcessor.processClearStaticDirectoryResponse(relativeLocalDirectory, repositoryDirectoryPath);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Set-sticky")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			final String tag = StreamUtilities.readLine(reader);
			responseProcessor.processSetStickyResponse(relativeLocalDirectory, repositoryFilePath, tag);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Clear-sticky")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			responseProcessor.processClearStickyResponse(relativeLocalDirectory, repositoryFilePath);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Notified")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			responseProcessor.processNotifiedResponse(relativeLocalDirectory, repositoryFilePath);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Removed")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFileName = StreamUtilities.readLine(reader);
			responseProcessor.processRemovedResponse(relativeLocalDirectory, repositoryFileName);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Remove-entry")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			responseProcessor.processRemoveEntryResponse(relativeLocalDirectory, repositoryFilePath);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Copy-file")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			final String newName = StreamUtilities.readLine(reader);
			responseProcessor.processCopyFileResponse(relativeLocalDirectory, repositoryFilePath, newName);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Mod-time")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String dateString = StreamUtilities.readLine(reader);

			final Date modifiedDate;
			try {
				modifiedDate = ResponseUtils.parseDateString(dateString);
			}
			catch (ParseException ex) {
				LOG.error("Could not parse '" + dateString + "'", ex);
				return null;
			}
			catch (RuntimeException ex) {
				LOG.error("Could not parse '" + dateString + "'", ex);
				return null;
			}

			responseProcessor.processModTimeResponse(modifiedDate);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Mode")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String mode = StreamUtilities.readLine(reader);
			responseProcessor.processModeResponse(mode);
			return null;
		}
		else if (responseName.equalsIgnoreCase("Template")) {
			final Reader reader = connectionStreams.getLoggedReader();
			final String relativeLocalDirectory = StreamUtilities.readLine(reader);
			final String repositoryFilePath = StreamUtilities.readLine(reader);
			final String lengthString = StreamUtilities.readLine(reader);
			final int length;
			try {
				// the following line can be sent by the server, when the template file is not available on the server
				// "E cvs server: Couldn't open rcsinfo template file /cvsroot/geotools/CVSROOT/gtTemplate: No such file or directory"
				length = Integer.parseInt(lengthString);
				responseProcessor.processTemplateResponse(relativeLocalDirectory, repositoryFilePath, length, connectionStreams);
			}
			catch (NumberFormatException ex) {
				// ignore
			}
			return null;
		}
		else if (responseName.equalsIgnoreCase("Module-expansion")) {
			final String localPath = StreamUtilities.readLine(connectionStreams.getLoggedReader());
			responseProcessor.processModuleExpansionResponse(localPath);
			return null;
		}
		else if (responseName.equalsIgnoreCase("ok")) {
			responseProcessor.processOkResponse();
			return Boolean.TRUE;
		}
		else if (responseName.equalsIgnoreCase("error")) {
			final String message = StreamUtilities.readLine(connectionStreams.getLoggedReader());
			responseProcessor.processErrorResponse(message);
			return Boolean.FALSE;
		}
		if (responseName.equalsIgnoreCase("Valid-requests")) {
			final String validRequests = StreamUtilities.readLine(connectionStreams.getLoggedReader());
			responseProcessor.processValidRequestsResponse(validRequests);
			return null;
		}

		throw new IOException("Unhandled response: " + responseName + ".");
	}

}
