/*
 * Copyright (C) 2013, Christian Halstrick <christian.halstrick@sap.com>
 * and other copyright owners as documented in the project's IP log.
 *
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Distribution License v1.0 which
 * accompanies this distribution, is reproduced below, and is
 * available at http://www.eclipse.org/org/documents/edl-v10.php
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 *
 * - Neither the name of the Eclipse Foundation, Inc. nor the
 *   names of its contributors may be used to endorse or promote
 *   products derived from this software without specific prior
 *   written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.eclipse.jgit.lib;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.jgit.lib.RebaseTodoLine.Action;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;

/**
 * Offers methods to read and write files formatted like the git-rebase-todo
 * file
 *
 * @since 3.2
 */
public class RebaseTodoFile {
	private Repository repo;

	/**
	 * @param repo
	 */
	public RebaseTodoFile(Repository repo) {
		this.repo = repo;
	}

	/**
	 * Read a file formatted like the git-rebase-todo file. The "done" file is
	 * also formatted like the git-rebase-todo file. These files can be found in
	 * .git/rebase-merge/ or .git/rebase-append/ folders.
	 *
	 * @param path
	 *            path to the file relative to the repository's git-dir. E.g.
	 *            "rebase-merge/git-rebase-todo" or "rebase-append/done"
	 * @param includeComments
	 *            <code>true</code> if also comments should be reported
	 * @return the list of steps
	 * @throws IOException
	 */
	public List<RebaseTodoLine> readRebaseTodo(String path,
			boolean includeComments) throws IOException {
		byte[] buf = IO.readFully(new File(repo.getDirectory(), path));
		int ptr = 0;
		int tokenBegin = 0;
		List<RebaseTodoLine> r = new LinkedList<>();
		while (ptr < buf.length) {
			tokenBegin = ptr;
			ptr = RawParseUtils.nextLF(buf, ptr);
			int lineStart = tokenBegin;
			int lineEnd = ptr - 2;
			if (lineEnd >= 0 && buf[lineEnd] == '\r')
				lineEnd--;
			// Handle comments
			if (buf[tokenBegin] == '#') {
				if (includeComments)
					parseComments(buf, tokenBegin, r, lineEnd);
			} else {
				// skip leading spaces+tabs+cr
				tokenBegin = nextParsableToken(buf, tokenBegin, lineEnd);
				// Handle empty lines (maybe empty after skipping leading
				// whitespace)
				if (tokenBegin == -1) {
					if (includeComments)
						r.add(new RebaseTodoLine(RawParseUtils.decode(buf,
								lineStart, 1 + lineEnd)));
					continue;
				}
				RebaseTodoLine line = parseLine(buf, tokenBegin, lineEnd);
				if (line == null)
					continue;
				r.add(line);
			}
		}
		return r;
	}

	private static void parseComments(byte[] buf, int tokenBegin,
			List<RebaseTodoLine> r, int lineEnd) {
		RebaseTodoLine line = null;
		String commentString = RawParseUtils.decode(buf,
				tokenBegin, lineEnd + 1);
		try {
			int skip = tokenBegin + 1; // skip '#'
			skip = nextParsableToken(buf, skip, lineEnd);
			if (skip != -1) {
				// try to parse the line as non-comment
				line = parseLine(buf, skip, lineEnd);
				// successfully parsed as non-comment line
				// mark this line as a comment explicitly
				line.setAction(Action.COMMENT);
				// use the read line as comment string
				line.setComment(commentString);
			}
		} catch (Exception e) {
			// parsing as non-comment line failed
			line = null;
		} finally {
			if (line == null)
				line = new RebaseTodoLine(commentString);
			r.add(line);
		}
	}

	/**
	 * Skip leading space, tab, CR and LF characters
	 *
	 * @param buf
	 * @param tokenBegin
	 * @param lineEnd
	 * @return the token within the range of the given {@code buf} that doesn't
	 *         need to be skipped, {@code -1} if no such token found within the
	 *         range (i.e. empty line)
	 */
	private static int nextParsableToken(byte[] buf, int tokenBegin, int lineEnd) {
		while (tokenBegin <= lineEnd
				&& (buf[tokenBegin] == ' ' || buf[tokenBegin] == '\t' || buf[tokenBegin] == '\r'))
			tokenBegin++;
		if (tokenBegin > lineEnd)
			return -1;
		return tokenBegin;
	}

	private static RebaseTodoLine parseLine(byte[] buf, int tokenBegin,
			int lineEnd) {
		RebaseTodoLine.Action action = null;
		AbbreviatedObjectId commit = null;

		int nextSpace = RawParseUtils.next(buf, tokenBegin, ' ');
		int tokenCount = 0;
		while (tokenCount < 3 && nextSpace < lineEnd) {
			switch (tokenCount) {
			case 0:
				String actionToken = new String(buf, tokenBegin, nextSpace
						- tokenBegin - 1);
				tokenBegin = nextSpace;
				action = RebaseTodoLine.Action.parse(actionToken);
				if (action == null)
					return null; // parsing failed
				break;
			case 1:
				nextSpace = RawParseUtils.next(buf, tokenBegin, ' ');
				String commitToken = new String(buf, tokenBegin, nextSpace
						- tokenBegin - 1);
				tokenBegin = nextSpace;
				commit = AbbreviatedObjectId.fromString(commitToken);
				break;
			case 2:
				return new RebaseTodoLine(action, commit, RawParseUtils.decode(
						buf, tokenBegin, 1 + lineEnd));
			}
			tokenCount++;
		}
		if (tokenCount == 2)
			return new RebaseTodoLine(action, commit, ""); //$NON-NLS-1$
		return null;
	}

	/**
	 * Write a file formatted like a git-rebase-todo file.
	 *
	 * @param path
	 *            path to the file relative to the repository's git-dir. E.g.
	 *            "rebase-merge/git-rebase-todo" or "rebase-append/done"
	 * @param steps
	 *            the steps to be written
	 * @param append
	 *            whether to append to an existing file or to write a new file
	 * @throws IOException
	 */
	public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps,
			boolean append) throws IOException {
		try (OutputStream fw = new BufferedOutputStream(new FileOutputStream(
				new File(repo.getDirectory(), path), append))) {
			StringBuilder sb = new StringBuilder();
			for (RebaseTodoLine step : steps) {
				sb.setLength(0);
				if (RebaseTodoLine.Action.COMMENT.equals(step.action))
					sb.append(step.getComment());
				else {
					sb.append(step.getAction().toToken());
					sb.append(" "); //$NON-NLS-1$
					sb.append(step.getCommit().name());
					sb.append(" "); //$NON-NLS-1$
					sb.append(step.getShortMessage().trim());
				}
				sb.append('\n');
				fw.write(Constants.encode(sb.toString()));
			}
		}
	}
}
