import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.spi.FileSystemProvider;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class TestPosixAttributeView {
	
	private static final String TEST_ZIP_NAME = "test-zip-file.zip";
	private static final String ENTRY_CONTENT = "foo-bar-content";
	private static final String ONLY_ENTRY_NAME = "noperm_entry";
	private static final Map<String, Object> POSIX_ENV;
	static {
		POSIX_ENV = new HashMap<>();
		POSIX_ENV.put("enablePosixFileAttributes", true);
	}
	private static final Map<String, Object> EMPTY_ENV = Collections.emptyMap();

    private void createTestZipFile(Path zpath) throws IOException {
        System.out.println("Debug: Creating " + zpath + "...");
		try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zpath.toFile()));
				ByteArrayInputStream fis = new ByteArrayInputStream(ENTRY_CONTENT.getBytes());) {

			ZipEntry zipEntry = new ZipEntry(ONLY_ENTRY_NAME);
			zos.putNextEntry(zipEntry);

			byte[] buffer = new byte[1024];
			int len;
			while ((len = fis.read(buffer)) > 0) {
				zos.write(buffer, 0, len);
			}
			zos.closeEntry();
		}
    }
    
    public void prepare(Path zip) {
    	try {
    		createTestZipFile(zip);
    	} catch (IOException e) {
    		throw new RuntimeException("Test preparation failed!");
    	}
    }
    
    public void runTest(Path zip, Map<String, Object> env) throws Exception {
    	PosixFileAttributeView view = null;
		boolean threwException = false;

		for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
			try (FileSystem zfs = provider.newFileSystem(zip, env)) {
				Path zipEntryPath = zfs.getPath("/" + ONLY_ENTRY_NAME);
				System.out.println("Debug: reading entry: " + zipEntryPath.toString());
				try {
					view = Files.getFileAttributeView(zipEntryPath, PosixFileAttributeView.class);
				} catch (UnsupportedOperationException e) {
					System.out.println("Debug: Files.getFileAttributeView() threw exception: " + e);
					threwException = true;
				}
				break;
			} catch (UnsupportedOperationException e) {
				// continue, wrong FS provider.
			}
		}
		String osName = System.getProperty("os.name");
		System.out.println("Debug: os.name == " + osName);
		int featureVersion = Runtime.version().feature();
		if (osName.toLowerCase().contains("win")) {
			// Windows branch
			if (view == null && !threwException) {
				System.out.println("Non-Windows Test PASSED! env=" + (env.isEmpty() ? "empty" : "posix") + " view=" + view + ", featureVersion: " + featureVersion);
			} else {
				throw new RuntimeException("Test failed!");
			}
		} else {
			if ((view == null && featureVersion >= 17 && !env.isEmpty()) || threwException) {
				throw new RuntimeException("Test failed! view=" + view);
			} else {
				System.out.println("Non-Windows Test PASSED! env=" + (env.isEmpty() ? "empty" : "posix") + " view=" + view + ", featureVersion: " + featureVersion);
			}
		}
    }
    
    public void cleanup(Path zip) {
    	try {
    		Files.deleteIfExists(zip);
    	} catch (IOException e) {
    		// ignore
    	}
    }

	public static void main(String[] args) throws Exception {
		Path zipFile = Path.of(TEST_ZIP_NAME);
		
		TestPosixAttributeView test = new TestPosixAttributeView();
		test.prepare(zipFile);
		try {
			test.runTest(zipFile, POSIX_ENV);
			test.runTest(zipFile, EMPTY_ENV);
		} finally {
			test.cleanup(zipFile);
		}
	}

}
