/*******************************************************************************
 * Copyright (c) 2020 Aston University.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the Eclipse
 * Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
 *
 * Contributors:
 *     Antonio Garcia-Dominguez - initial API and implementation
 ******************************************************************************/
package org.eclipse.hawk.localfolder;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.eclipse.hawk.core.IModelIndexer;
import org.eclipse.hawk.core.VcsChangeType;
import org.eclipse.hawk.core.VcsCommitItem;
import org.eclipse.hawk.core.util.DefaultConsole;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class LocalFolderTest {

	@Rule
	public TemporaryFolder folder = new TemporaryFolder();
	private File root;
	private LocalFolder vcs;

	@Before
	public void setup() throws Exception {
		final IModelIndexer indexer = mock(IModelIndexer.class);
		when(indexer.getConsole()).thenReturn(new DefaultConsole());

		vcs = new LocalFolder();
		vcs.init(folder.getRoot().getAbsolutePath(), indexer);
		vcs.run();

		root = folder.getRoot();
	}

	protected File write(final String filename, final String text) throws FileNotFoundException {
		final File f = new File(root, filename);
		try (PrintWriter pw = new PrintWriter(f)) {
			pw.println(text);
		}
		return f;
	}

	@Test
	public void empty() throws Exception {
		assertEquals(0, vcs.getDelta(null).size());
	}

	@Test
	public void addFile() throws Exception {
		write("a.txt", "hello");
		final String firstRevision = vcs.getCurrentRevision();

		List<VcsCommitItem> delta = vcs.getDelta(LocalFolder.FIRST_REV);
		assertEquals(1, delta.size());

		VcsCommitItem item = delta.get(0);
		assertEquals("/a.txt", item.getPath());
		assertEquals(firstRevision, item.getCommit().getRevision());

		assertEquals(0, vcs.getDelta(firstRevision).size());
		assertEquals(firstRevision, vcs.getCurrentRevision());
	}

	@Test
	public void deleteFile() throws Exception {
		File f = write("a.txt", "hello");
		final String revAdded = vcs.getCurrentRevision();

		List<VcsCommitItem> delta = vcs.getDelta(LocalFolder.FIRST_REV);
		assertEquals(1, delta.size());
		assertEquals(VcsChangeType.UPDATED, delta.get(0).getChangeType());
		assertEquals(revAdded, delta.get(0).getCommit().getRevision());

		// Takes into account lastModified() millisecond resolution since Java 9
		synchronized (this) {
			Thread.sleep(100);
		}

		f.delete();
		delta = vcs.getDelta(revAdded);
		assertEquals(1, delta.size());
		assertEquals(VcsChangeType.DELETED, delta.get(0).getChangeType());
		final String revDeleted = delta.get(0).getCommit().getRevision();
		assertNotEquals(revDeleted, revAdded);
		assertEquals(vcs.getCurrentRevision(), revDeleted);
	}

	@Test
	public void updateFile() throws Exception {
		File f = write("a.txt", "hello");
		String revAdded = vcs.getCurrentRevision();

		List<VcsCommitItem> delta = vcs.getDelta(LocalFolder.FIRST_REV);
		assertEquals(1, delta.size());
		assertEquals(revAdded, delta.get(0).getCommit().getRevision());

		// Takes into account lastModified() millisecond resolution since Java 9
		synchronized (this) {
			Thread.sleep(100);
		}

		write(f.getName(), "bye");
		delta = vcs.getDelta(revAdded);
		assertEquals(1, delta.size());
		assertEquals(VcsChangeType.UPDATED, delta.get(0).getChangeType());
		final String revUpdated = delta.get(0).getCommit().getRevision();
		assertNotEquals(revAdded, revUpdated);
	}

	@Test
	public void copyFile() throws Exception {
		write("a.txt", "hello");
		write("build.properties", "bye");

		List<VcsCommitItem> delta = vcs.getDelta(LocalFolder.FIRST_REV);
		assertEquals(2, delta.size());
		final String revAdded = delta.get(0).getCommit().getRevision();

		FileUtils.copyFileToDirectory(new File("build.properties"), folder.getRoot());
		assertNotEquals(vcs.getCurrentRevision(), revAdded);

		delta = vcs.getDelta(revAdded);
		assertEquals(1, delta.size());
		assertEquals("/build.properties", delta.get(0).getPath());
		final String revCopied = delta.get(0).getCommit().getRevision();
		assertNotEquals(revAdded, revCopied);
		System.out.println(revAdded + ", " + revCopied);
	}

	@Test
	public void renameFile() throws Exception {
		File f = write("a.txt", "hello");

		List<VcsCommitItem> delta = vcs.getDelta(LocalFolder.FIRST_REV);
		assertEquals(1, delta.size());
		final String revAdded = delta.get(0).getCommit().getRevision();

		f.renameTo(new File(f.getParentFile(), "b.txt"));
		assertNotEquals(vcs.getCurrentRevision(), revAdded);

		delta = vcs.getDelta(revAdded);
		assertEquals(2, delta.size());
		assertEquals("/a.txt", delta.get(0).getPath());
		assertEquals(VcsChangeType.DELETED, delta.get(0).getChangeType());
		assertEquals("/b.txt", delta.get(1).getPath());
		assertEquals(VcsChangeType.UPDATED, delta.get(1).getChangeType());
		final String revCopied = delta.get(0).getCommit().getRevision();
		assertNotEquals(revAdded, revCopied);
		System.out.println(revAdded + ", " + revCopied);
	}

}
