// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 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 HOLDER 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 jodd.io;

import jodd.io.findfile.FindFile;
import jodd.io.findfile.WildcardFindFile;
import jodd.mutable.MutableInteger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class FindFileTest {

	protected String dataRoot;

	@BeforeEach
	void setUp() {
		if (dataRoot != null) {
			return;
		}
		final URL data = FindFileTest.class.getResource("data");
		dataRoot = data.getFile();
	}

	@Test
	void testUncompleted() {
		final List<File> fileList = FindFile.create().findAll();
		assertEquals(0, fileList.size());
	}

	@Test
	void testTwoAccept() {
		final FindFile ff = new WildcardFindFile()
						.include("**/*file/a.png")
						.include("**/*file/a.txt")
						.recursive(true)
						.includeDirs(true)
						.searchPath(dataRoot);

		final MutableInteger countFiles = new MutableInteger();
		final MutableInteger countDirs = new MutableInteger();

		ff.forEach(f -> {
				if (f.isDirectory()) {
					countDirs.value++;
				} else {
					countFiles.value++;
					String path = f.getAbsolutePath();
					path = FileNameUtil.separatorsToUnix(path);
					if (!path.startsWith("/")) {
						path = '/' + path;
					}
					final boolean matched =
						path.equals(dataRoot + "/file/a.png") ||
							path.equals(dataRoot + "/file/a.txt");

				assertTrue(matched);
			}
		});

		assertEquals(0, countDirs.value);
		assertEquals(2, countFiles.value);
	}

	@Test
	void testWildcardFile() {
		final FindFile ff = new WildcardFindFile()
				.include("**/*file/a*")
				.recursive(true)
				.includeDirs(true)
				.searchPath(dataRoot);

		int countDirs = 0;
		int countFiles = 0;

		File f;
		while ((f = ff.nextFile()) != null) {
			if (f.isDirectory()) {
				countDirs++;
			} else {
				countFiles++;
				String path = f.getAbsolutePath();
				path = FileNameUtil.separatorsToUnix(path);
				if (!path.startsWith("/")) {
					path = '/' + path;
				}
				final boolean matched =
						path.equals(dataRoot + "/file/a.png") ||
								path.equals(dataRoot + "/file/a.txt");

				assertTrue(matched);

			}
		}

		assertEquals(0, countDirs);
		assertEquals(2, countFiles);

		ff.searchPath(dataRoot);

		final MutableInteger countDirs2 = new MutableInteger();
		final MutableInteger countFiles2 = new MutableInteger();

		ff.forEach(file -> {
			if (file.isDirectory()) {
				countDirs2.value++;
			} else {
				countFiles2.value++;
				String path = file.getAbsolutePath();
				path = FileNameUtil.separatorsToUnix(path);
				if (!path.startsWith("/")) {
					path = '/' + path;
				}

				final boolean matched =
						path.equals(dataRoot + "/file/a.png") ||
								path.equals(dataRoot + "/file/a.txt");

				assertTrue(matched);
			}
		});

		assertEquals(0, countDirs2.get());
		assertEquals(2, countFiles2.get());
	}

	@Test
	void testWildcardPath() {
		final FindFile ff = new WildcardFindFile()
				.include("**/file/*")
				.recursive(true)
				.includeDirs(true)
				.searchPath(dataRoot);

		int countDirs = 0;
		int countFiles = 0;

		File f;
		while ((f = ff.nextFile()) != null) {
			if (f.isDirectory()) {
				countDirs++;
			} else {
				countFiles++;
				String path = f.getAbsolutePath();
				path = FileNameUtil.separatorsToUnix(path);
				if (!path.startsWith("/")) {
					path = '/' + path;
				}

				final boolean matched =
						path.equals(dataRoot + "/file/a.png") ||
								path.equals(dataRoot + "/file/a.txt");

				assertTrue(matched);
			}
		}

		assertEquals(0, countDirs);
		assertEquals(2, countFiles);
	}

	@Test
	void testRegexp() {
		final FindFile ff = FindFile.createRegExpFF()
				.include(".*/a[.].*")
				.recursive(true)
				.includeDirs(true)
				.searchPath(dataRoot);

		int countDirs = 0;
		int countFiles = 0;

		File f;
		while ((f = ff.nextFile()) != null) {
			if (f.isDirectory()) {
				countDirs++;
			} else {
				countFiles++;
				String path = f.getAbsolutePath();
				path = FileNameUtil.separatorsToUnix(path);
				if (!path.startsWith("/")) {
					path = '/' + path;
				}

				final boolean matched =
						path.equals(dataRoot + "/file/a.png") ||
								path.equals(dataRoot + "/file/a.txt");

				assertTrue(matched);

			}
		}

		assertEquals(0, countDirs);
		assertEquals(2, countFiles);
	}

	@Test
	void testFindAll() {
		final List<File> foundedFiles = new WildcardFindFile()
			.include("**/*file/a*")
			.recursive(true)
			.includeDirs(true)
			.searchPath(dataRoot)
			.findAll();

		assertEquals(2, foundedFiles.size());

		final List<String> names = foundedFiles.stream().map(File::getName).collect(Collectors.toList());

		assertTrue(names.contains("a.png"));
		assertTrue(names.contains("a.txt"));
	}

	@Test
	void testConsumer() {
		final List<File> foundedFiles = new ArrayList<>();

		WildcardFindFile.create()
			.include("**/*file/a*")
			.recursive(true)
			.includeDirs(true)
			.onFile(foundedFiles::add)
			.searchPath(dataRoot)
			.findAll();

		assertEquals(2, foundedFiles.size());

		final List<String> names = foundedFiles.stream().map(File::getName).collect(Collectors.toList());

		assertTrue(names.contains("a.png"));
		assertTrue(names.contains("a.txt"));
	}
}
