/*
 *                 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.text.*;
import java.util.*;

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

/**
 * @author Thomas Singer
 */
final class EditorsMessageParser extends AbstractMessageParser {

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

	private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMM dd HH:mm:ss yyyy", Locale.US);

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

	private final IEventSender eventSender;
	private final ILocalFileSystem localFileSystem;
	private final Set<File> fileSet = new HashSet<File>();

	private transient EditorsFileInfoContainer editorsFileInfo;

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

	public EditorsMessageParser(IEventSender eventSender, final ILocalFileSystem localFileSystem, ICvsFiles cvsFiles) {
		this.eventSender = eventSender;
		this.localFileSystem = localFileSystem;

		try {
			cvsFiles.visitFiles(new ICvsFilesVisitor() {
				public void handleFile(FsFilePath fsFile, Entry entry, boolean exists) {
					final File file = localFileSystem.getFile(fsFile);
					fileSet.add(file);
				}
			});
		}
		catch (CommandAbortedException e) {
			e.printStackTrace();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}

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

	@Override
	public void parseLine(String line, boolean isErrorMessage) {
		if (isErrorMessage) {
			return;
		}

		final TabStringTokenizer tokenizer = new TabStringTokenizer(line);
		final String fileName = tokenizer.nextToken();
		final String user = tokenizer.nextToken();
		final String dateString = tokenizer.nextToken();
		final String clientName = tokenizer.nextToken();
		final String editDirectory = tokenizer.nextToken();
		if (editDirectory == null) {
			return;
		}

		if (fileName.length() > 0) {
			final File file = localFileSystem.getFile(fileName);
			if (editorsFileInfo != null && !editorsFileInfo.getFile().equals(file)) {
				fireFileInfoEvent(editorsFileInfo, true);
				editorsFileInfo = null;
			}
			if (editorsFileInfo == null) {
				editorsFileInfo = new EditorsFileInfoContainer(file);
			}
		}
		else {
			if (editorsFileInfo == null) {
				return;
			}
		}

		try {
			final Date date = parseDate(dateString);

			editorsFileInfo.addEditor(date, user, clientName, editDirectory);
		}
		catch (ParseException ex) {
			// ignore
		}
	}

	@Override
	public void outputDone() {
		if (editorsFileInfo != null) {
			fireFileInfoEvent(editorsFileInfo, true);
			editorsFileInfo = null;
		}

		for (Iterator<File> it = fileSet.iterator(); it.hasNext();) {
			final File file = it.next();
			fireFileInfoEvent(new EditorsFileInfoContainer(file), false);
			it.remove();
		}
	}

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

	private void fireFileInfoEvent(EditorsFileInfoContainer editorsFileInfo, boolean remove) {
		eventSender.notifyFileInfoListeners(editorsFileInfo);

		if (remove) {
			fileSet.remove(editorsFileInfo.getFile());
		}
	}

	private static Date parseDate(String dateString) throws ParseException {
		// strip day of week
		final int firstSpaceIndex = Math.max(dateString.indexOf(' '), 0);
		// strip time zone
		int lastSpaceIndex = dateString.lastIndexOf(' ');
		if (lastSpaceIndex < 0) {
			throw new ParseException("could not find last space in '" + dateString + "'", 0);
		}

		if (getDigitCount(lastSpaceIndex, dateString) == 4) {
			lastSpaceIndex = dateString.length();
		}

		dateString = dateString.substring(firstSpaceIndex, lastSpaceIndex).trim();

		return DATE_FORMAT.parse(dateString);
	}

	private static int getDigitCount(int lastSpaceIndex, String dateString) {
		int digitCount = 0;
		for (int i = lastSpaceIndex + 1, length = dateString.length(); i < length; i++, digitCount++) {
			final char chr = dateString.charAt(i);
			if (chr < '0' || chr > '9') {
				return 0;
			}
		}
		return digitCount;
	}
}
