diff --git a/pom.xml b/pom.xml index 5a043114d..f3dfef482 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ org.janelia.saalfeldlab.paintera.Paintera Paintera paintera - 1.3.0 + 1.3.4 javafx.base,javafx.controls,javafx.fxml,javafx.media,javafx.swing,javafx.web,javafx.graphics,java.naming,java.management,java.sql UTF-8 f918b6f9-8685-4b50-9fbd-9be7a1209249 diff --git a/src/main/java/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDatasetHandler.java b/src/main/java/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDatasetHandler.java index 1bb58cc56..f5287ef96 100644 --- a/src/main/java/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDatasetHandler.java +++ b/src/main/java/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDatasetHandler.java @@ -53,13 +53,13 @@ private static void createAndAddNewLabelDataset( public static void createAndAddNewLabelDataset( final PainteraBaseView pbv, - final Supplier projecDirectory, + final Supplier projectDirectory, final Consumer exceptionHandler, final Source currentSource, final Source... allSources) { try { - createAndAddNewLabelDataset(pbv, projecDirectory, currentSource, allSources); + createAndAddNewLabelDataset(pbv, projectDirectory, currentSource, allSources); } catch (final Exception e) { exceptionHandler.accept(e); } diff --git a/src/main/java/org/janelia/saalfeldlab/util/n5/N5Data.java b/src/main/java/org/janelia/saalfeldlab/util/n5/N5Data.java index 5f106925f..52f5ebfca 100644 --- a/src/main/java/org/janelia/saalfeldlab/util/n5/N5Data.java +++ b/src/main/java/org/janelia/saalfeldlab/util/n5/N5Data.java @@ -35,7 +35,6 @@ import org.janelia.saalfeldlab.n5.imglib2.N5Utils; import org.janelia.saalfeldlab.n5.universe.metadata.N5SpatialDatasetMetadata; import org.janelia.saalfeldlab.n5.universe.metadata.SpatialMultiscaleMetadata; -import org.janelia.saalfeldlab.paintera.Paintera; import org.janelia.saalfeldlab.paintera.cache.WeakRefVolatileCache; import org.janelia.saalfeldlab.paintera.data.DataSource; import org.janelia.saalfeldlab.paintera.data.n5.N5DataSource; @@ -69,7 +68,7 @@ public class N5Data { private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param priority in fetching queue * @param data type @@ -95,7 +94,7 @@ ImagesWithTransform openRaw( } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param transform transforms voxel data into real world coordinates * @param priority in fetching queue @@ -131,7 +130,7 @@ DataSource openRawAsSource( } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param transform transforms voxel data into real world coordinates * @param priority in fetching queue @@ -163,7 +162,7 @@ DataSource openScalarAsSource( } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param transform transforms voxel data into real world coordinates * @param priority in fetching queue @@ -197,7 +196,7 @@ DataSource openScalarAsSource( } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param transform transforms voxel data into real world coordinates * @param priority in fetching queue @@ -256,7 +255,7 @@ ImagesWithTransform openRaw( } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param transform transforms voxel data into real world coordinates * @param priority in fetching queue @@ -287,7 +286,7 @@ ImagesWithTransform openRaw( } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param priority in fetching queue * @param data type @@ -314,7 +313,7 @@ ImagesWithTransform[] openRawMultiscale( } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param resolution voxel resolution * @param offset offset in real world coordinates @@ -419,7 +418,7 @@ ImagesWithTransform[] openRawMultiscale( } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param transform transforms voxel data into real world coordinates * @param priority in fetching queue @@ -481,7 +480,7 @@ public static ImagesWithTransform } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param priority in fetching queue * @return image data with cache invalidation @@ -504,7 +503,7 @@ public static ImagesWithTransform } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param resolution voxel size * @param offset in world coordinates @@ -560,7 +559,7 @@ public static ImagesWithTransform } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param priority in fetching queue * @return multi-scale image data with cache invalidation @@ -583,7 +582,7 @@ public static ImagesWithTransform[ } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param resolution voxel size * @param offset in world coordinates @@ -652,7 +651,7 @@ public static ImagesWithTransform[ } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param transform from voxel space to world coordinates * @param priority in fetching queue @@ -705,7 +704,7 @@ public static ImagesWithTransform[ } /** - * @param reader container + * @param reader N5Reader * @param dataset dataset * @param transform transforms voxel data into real world coordinates * @param priority in fetching queue @@ -716,8 +715,7 @@ public static ImagesWithTransform[ * @throws IOException if any N5 operation throws {@link IOException} */ @SuppressWarnings("unchecked") - public static , T extends NativeType> DataSource - openAsLabelSource( + public static , T extends NativeType> DataSource openAsLabelSource( final N5Reader reader, final String dataset, final AffineTransform3D transform, @@ -731,8 +729,8 @@ public static ImagesWithTransform[ } /** - * @param container container - * @param group target group in {@code container} + * @param writer N5Writer + * @param group target group in {@code writer} * @param dimensions size * @param blockSize chunk size * @param resolution voxel size @@ -743,7 +741,7 @@ public static ImagesWithTransform[ * @throws IOException if any n5 operation throws {@link IOException} */ public static void createEmptyLabelDataset( - final String container, + final N5Writer writer, final String group, final long[] dimensions, final int[] blockSize, @@ -753,12 +751,12 @@ public static void createEmptyLabelDataset( @Nullable final int[] maxNumEntries, final boolean labelMultiset) throws IOException { - createEmptyLabelDataset(container, group, dimensions, blockSize, resolution, offset, relativeScaleFactors, maxNumEntries, labelMultiset, false); + createEmptyLabelDataset(writer, group, dimensions, blockSize, resolution, offset, relativeScaleFactors, maxNumEntries, labelMultiset, false); } /** - * @param container container - * @param group target group in {@code container} + * @param writer N5Writer + * @param group target group in {@code writer} * @param dimensions size * @param blockSize chunk size * @param resolution voxel size @@ -771,7 +769,7 @@ public static void createEmptyLabelDataset( * already exists and {@code ignorExisting} is {@code false} */ public static void createEmptyLabelDataset( - final String container, + final N5Writer writer, final String group, final long[] dimensions, final int[] blockSize, @@ -784,35 +782,35 @@ public static void createEmptyLabelDataset( final Map pd = new HashMap<>(); pd.put("type", "label"); - final N5Writer n5 = Paintera.getN5Factory().newWriter(container); final String uniqueLabelsGroup = String.format("%s/unique-labels", group); - if (!ignoreExisiting && n5.datasetExists(group)) - throw new IOException(String.format("Dataset `%s' already exists in container `%s'", group, container)); + var n5Uri = writer.getURI(); + if (!ignoreExisiting && writer.datasetExists(group)) + throw new IOException(String.format("Dataset `%s' already exists in container `%s'", group, n5Uri)); - if (!n5.exists(group)) - n5.createGroup(group); + if (!writer.exists(group)) + writer.createGroup(group); - if (!ignoreExisiting && n5.getAttribute(group, N5Helpers.PAINTERA_DATA_KEY, JsonObject.class) != null) - throw new IOException(String.format("Group '%s' already exists in container '%s' and is a Paintera dataset", group, container)); + if (!ignoreExisiting && writer.getAttribute(group, N5Helpers.PAINTERA_DATA_KEY, JsonObject.class) != null) + throw new IOException(String.format("Group '%s' already exists in container '%s' and is a Paintera dataset", group, n5Uri)); - if (!ignoreExisiting && n5.exists(uniqueLabelsGroup)) - throw new IOException(String.format("Unique labels group '%s' already exists in container '%s' -- conflict likely.", uniqueLabelsGroup, container)); + if (!ignoreExisiting && writer.exists(uniqueLabelsGroup)) + throw new IOException(String.format("Unique labels group '%s' already exists in container '%s' -- conflict likely.", uniqueLabelsGroup, n5Uri)); - n5.setAttribute(group, N5Helpers.PAINTERA_DATA_KEY, pd); - n5.setAttribute(group, N5Helpers.MAX_ID_KEY, 0L); + writer.setAttribute(group, N5Helpers.PAINTERA_DATA_KEY, pd); + writer.setAttribute(group, N5Helpers.MAX_ID_KEY, 0L); final String dataGroup = String.format("%s/data", group); - n5.createGroup(dataGroup); + writer.createGroup(dataGroup); - n5.setAttribute(dataGroup, N5Helpers.MULTI_SCALE_KEY, true); - n5.setAttribute(dataGroup, N5Helpers.OFFSET_KEY, offset); - n5.setAttribute(dataGroup, N5Helpers.RESOLUTION_KEY, resolution); - n5.setAttribute(dataGroup, N5Helpers.IS_LABEL_MULTISET_KEY, labelMultisetType); + writer.setAttribute(dataGroup, N5Helpers.MULTI_SCALE_KEY, true); + writer.setAttribute(dataGroup, N5Helpers.OFFSET_KEY, offset); + writer.setAttribute(dataGroup, N5Helpers.RESOLUTION_KEY, resolution); + writer.setAttribute(dataGroup, N5Helpers.IS_LABEL_MULTISET_KEY, labelMultisetType); - n5.createGroup(uniqueLabelsGroup); - n5.setAttribute(uniqueLabelsGroup, N5Helpers.MULTI_SCALE_KEY, true); + writer.createGroup(uniqueLabelsGroup); + writer.setAttribute(uniqueLabelsGroup, N5Helpers.MULTI_SCALE_KEY, true); final String scaleDatasetPattern = String.format("%s/s%%d", dataGroup); final String scaleUniqueLabelsPattern = String.format("%s/s%%d", uniqueLabelsGroup); @@ -830,17 +828,17 @@ public static void createEmptyLabelDataset( final String uniqeLabelsDataset = String.format(scaleUniqueLabelsPattern, scaleLevel); if (labelMultisetType) { - n5.createDataset(dataset, scaledDimensions, blockSize, DataType.UINT8, new GzipCompression()); + writer.createDataset(dataset, scaledDimensions, blockSize, DataType.UINT8, new GzipCompression()); final int maxNum = downscaledLevel < 0 ? -1 : maxNumEntries[downscaledLevel]; - n5.setAttribute(dataset, N5Helpers.MAX_NUM_ENTRIES_KEY, maxNum); - n5.setAttribute(dataset, N5Helpers.IS_LABEL_MULTISET_KEY, true); + writer.setAttribute(dataset, N5Helpers.MAX_NUM_ENTRIES_KEY, maxNum); + writer.setAttribute(dataset, N5Helpers.IS_LABEL_MULTISET_KEY, true); } else - n5.createDataset(dataset, scaledDimensions, blockSize, DataType.UINT64, new GzipCompression()); + writer.createDataset(dataset, scaledDimensions, blockSize, DataType.UINT64, new GzipCompression()); - n5.createDataset(uniqeLabelsDataset, scaledDimensions, blockSize, DataType.UINT64, new GzipCompression()); + writer.createDataset(uniqeLabelsDataset, scaledDimensions, blockSize, DataType.UINT64, new GzipCompression()); if (scaleLevel != 0) { - n5.setAttribute(dataset, N5Helpers.DOWNSAMPLING_FACTORS_KEY, accumulatedFactors); - n5.setAttribute(uniqeLabelsDataset, N5Helpers.DOWNSAMPLING_FACTORS_KEY, accumulatedFactors); + writer.setAttribute(dataset, N5Helpers.DOWNSAMPLING_FACTORS_KEY, accumulatedFactors); + writer.setAttribute(uniqeLabelsDataset, N5Helpers.DOWNSAMPLING_FACTORS_KEY, accumulatedFactors); } } } diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt index 82596a661..2f0420c8d 100644 --- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt +++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/PainteraMainWindow.kt @@ -117,8 +117,8 @@ class PainteraMainWindow(val gateway: PainteraGateway = PainteraGateway()) { { projectDirectory.actualDirectory.absolutePath }, { indexToState[it] }) val gson = builder.create() - val json = projectDirectory.actualDirectory - ?.let { Paintera.n5Factory.openReader(it.absolutePath).getAttribute("/", PAINTERA_KEY, JsonElement::class.java) } + val json = projectDirectory.actualDirectory.absolutePath + .let { Paintera.n5Factory.openReader(it).getAttribute("/", PAINTERA_KEY, JsonElement::class.java) } ?.takeIf { it.isJsonObject } ?.asJsonObject Paintera.n5Factory.gsonBuilder(builder) @@ -156,7 +156,7 @@ class PainteraMainWindow(val gateway: PainteraGateway = PainteraGateway()) { fun save(notify: Boolean = true) { - /* Not allowd to save if any source is RAI */ + /* Not allowed to save if any source is RAI */ baseView.sourceInfo().canSourcesBeSerialized().nullable?.let { reasonSoureInfoCannotBeSerialized -> val alert = PainteraAlerts.alert(Alert.AlertType.WARNING) alert.title = "Cannot Serialize All Sources" @@ -184,7 +184,7 @@ class PainteraMainWindow(val gateway: PainteraGateway = PainteraGateway()) { } } - /* Change back to the currect mode. */ + /* Change back to the correct mode. */ baseView.changeMode(curMode) } @@ -331,11 +331,9 @@ class PainteraMainWindow(val gateway: PainteraGateway = PainteraGateway()) { private const val TILDE = "~" - private fun replaceUserHomeWithTilde(path: String) = if (path.startsWith(USER_HOME)) path.replaceFirst(USER_HOME, TILDE) else path + internal fun String.homeToTilde() = if (startsWith(USER_HOME)) replaceFirst(USER_HOME, TILDE) else this - internal fun String.homeToTilde() = replaceUserHomeWithTilde(this) - - internal fun String.tildeToHome() = if (this.startsWith(TILDE)) this.replaceFirst(TILDE, USER_HOME) else this + internal fun String.tildeToHome() = if (startsWith(TILDE)) replaceFirst(TILDE, USER_HOME) else this } diff --git a/src/main/kotlin/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDataset.kt b/src/main/kotlin/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDataset.kt index 2e05a36f8..1de3afa03 100644 --- a/src/main/kotlin/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDataset.kt +++ b/src/main/kotlin/org/janelia/saalfeldlab/paintera/ui/dialogs/create/CreateDataset.kt @@ -40,6 +40,7 @@ import org.janelia.saalfeldlab.fx.ui.ObjectField.Companion.stringField import org.janelia.saalfeldlab.fx.ui.ObjectField.SubmitOn import org.janelia.saalfeldlab.fx.ui.SpatialField import org.janelia.saalfeldlab.fx.util.InvokeOnJavaFXApplicationThread +import org.janelia.saalfeldlab.n5.N5KeyValueWriter import org.janelia.saalfeldlab.paintera.Constants import org.janelia.saalfeldlab.paintera.Paintera import org.janelia.saalfeldlab.paintera.Paintera.Companion.n5Factory @@ -47,6 +48,7 @@ import org.janelia.saalfeldlab.paintera.Style.ADD_GLYPH import org.janelia.saalfeldlab.paintera.Style.REMOVE_GLYPH import org.janelia.saalfeldlab.paintera.data.mask.MaskedSource import org.janelia.saalfeldlab.paintera.data.n5.N5DataSource +import org.janelia.saalfeldlab.paintera.paintera import org.janelia.saalfeldlab.paintera.state.SourceState import org.janelia.saalfeldlab.paintera.state.metadata.MetadataState import org.janelia.saalfeldlab.paintera.state.metadata.MetadataUtils.Companion.createMetadataState @@ -117,7 +119,7 @@ class CreateDataset(private val currentSource: Source<*>?, vararg allSources: So } } - private val n5Container: DirectoryField = DirectoryField(System.getProperty("user.home"), FIELD_WIDTH) + private val n5Container: DirectoryField = DirectoryField(paintera.projectDirectory.actualDirectory, FIELD_WIDTH) private val dataset = stringField("", *SubmitOn.entries.toTypedArray()).apply { textField.textProperty().addListener { _, _, newv: String? -> if (!nameField.manuallyNamed && newv != null) { @@ -253,7 +255,7 @@ class CreateDataset(private val currentSource: Source<*>?, vararg allSources: So headerText = "Create new Label dataset" dialogPane.content = pane dialogPane.lookupButton(ButtonType.OK).addEventFilter(ActionEvent.ACTION) { e: ActionEvent -> - val container = n5Container.directoryProperty().value!!.absolutePath + val container = n5Container.directoryProperty().value!! val dataset = dataset.value val name = nameField.text LOG.debug { "Trying to create empty label dataset `$dataset' in container `$container'"} @@ -274,8 +276,13 @@ class CreateDataset(private val currentSource: Source<*>?, vararg allSources: So } try { + val writer = n5Factory.newWriter(container.absolutePath) + + if (labelMultiset.isSelected && writer !is N5KeyValueWriter) + throw UnsupportedOperationException("LabelMultisetType Label dataset only supported for N5 datasets") + N5Data.createEmptyLabelDataset( - container, + writer, dataset, dimensions.asLongArray(), blockSize.asIntArray(), @@ -286,7 +293,6 @@ class CreateDataset(private val currentSource: Source<*>?, vararg allSources: So labelMultiset.isSelected ) - val writer = n5Factory.openWriter(container) N5Helpers.parseMetadata(writer, true).ifPresent { _ -> val containerState = N5ContainerState(writer) createMetadataState(containerState, dataset).ifPresent { metadataStateProp.set(it) } diff --git a/src/main/kotlin/org/janelia/saalfeldlab/util/n5/N5Helpers.kt b/src/main/kotlin/org/janelia/saalfeldlab/util/n5/N5Helpers.kt index b52e27f91..5bed78804 100644 --- a/src/main/kotlin/org/janelia/saalfeldlab/util/n5/N5Helpers.kt +++ b/src/main/kotlin/org/janelia/saalfeldlab/util/n5/N5Helpers.kt @@ -49,9 +49,7 @@ import org.janelia.saalfeldlab.util.n5.metadata.N5PainteraDataMultiScaleMetadata import org.janelia.saalfeldlab.util.n5.metadata.N5PainteraLabelMultiScaleGroup.PainteraLabelMultiScaleParser import org.janelia.saalfeldlab.util.n5.metadata.N5PainteraRawMultiScaleGroup.PainteraRawMultiScaleParser import org.janelia.saalfeldlab.util.n5.universe.N5ContainerDoesntExist -import org.slf4j.LoggerFactory import java.io.IOException -import java.lang.invoke.MethodHandles import java.util.* import java.util.List import java.util.concurrent.ExecutorService @@ -791,7 +789,9 @@ object N5Helpers { ?.asJsonObject?.get("data") ?.asJsonObject?.let { it.get("basePath") ?: it.get("file") } ?.asString - val uri = fromClassInfo ?: json[URI]?.asString ?: paintera.projectDirectory.actualDirectory.toURI().toString() + val uri = fromClassInfo + ?: json[URI]?.asString + ?: paintera.projectDirectory.actualDirectory.absolutePath return getN5ContainerWithRetryPrompt(uri) } diff --git a/src/main/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCache.kt b/src/main/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCache.kt index 0f4b30447..586ebba92 100644 --- a/src/main/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCache.kt +++ b/src/main/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCache.kt @@ -7,18 +7,56 @@ import org.janelia.saalfeldlab.n5.N5Writer import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader import org.janelia.saalfeldlab.n5.universe.N5Factory import org.slf4j.LoggerFactory +import java.io.File import java.lang.invoke.MethodHandles +import java.net.URI +import java.nio.file.Path +import java.nio.file.Paths +import kotlin.io.path.toPath class N5FactoryWithCache : N5Factory() { companion object { private val LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()) + + private const val ZGROUP = ".zgroup" + private const val ZARRAY = ".zarray" + private const val ZATTRS = ".zattrs" + private const val N5_ATTRIBUTES = "attributes.json" + + /** Check for existing of N5 and zarr specific files to indicate the format + **/ + internal fun File.guessStorageFromFormatSpecificFiles() : StorageFormat? = when { + resolve(N5_ATTRIBUTES).exists() -> StorageFormat.N5 + listOf(ZGROUP, ZARRAY, ZATTRS).any { resolve(it).exists() } -> StorageFormat.ZARR + else -> null + } } private val writerCache = HashMap() private val readerCache = HashMap() - override fun openReader(uri: String): N5Reader { - return getFromReaderCache(uri) ?: getFromWriterCache(uri) ?: super.openReader(uri).let { + + private fun parseUriWithN5Default(uri: String) : Pair { + return StorageFormat.parseUri(uri).run { + val fileBasedFormatCheck = if (a == null && (b.scheme == null || b.scheme == "file")) { + File(b.path).guessStorageFromFormatSpecificFiles() + } else null + (a ?: fileBasedFormatCheck ?: StorageFormat.N5) to b + } + } + + private fun openWriterDefaultN5(uri: String) : N5Writer { + val (format, asUri) = parseUriWithN5Default(uri) + return super.openWriter(format, asUri) + } + + private fun openReaderDefaultN5(uri: String) : N5Reader { + val (format, asUri) = parseUriWithN5Default(uri) + return super.openReader(format, asUri) + } + + override fun openReader(uri: String): N5Reader { + return getFromReaderCache(uri) ?: getFromWriterCache(uri) ?: openReaderDefaultN5(uri).let { if (containerIsReadable(it)) { readerCache[uri] = it it @@ -130,7 +168,7 @@ class N5FactoryWithCache : N5Factory() { } private fun createAndCacheN5Writer(uri: String): N5Writer { - val n5Writer = super.openWriter(uri) + val n5Writer = openWriterDefaultN5(uri) /* See if we have write permissions before we declare success */ n5Writer.setAttribute("/", N5Reader.VERSION_KEY, n5Writer.version.toString()) if (readerCache[uri] == null) { diff --git a/src/test/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCacheTest.kt b/src/test/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCacheTest.kt new file mode 100644 index 000000000..f07b95e81 --- /dev/null +++ b/src/test/kotlin/org/janelia/saalfeldlab/util/n5/universe/N5FactoryWithCacheTest.kt @@ -0,0 +1,43 @@ +package org.janelia.saalfeldlab.util.n5.universe + +import org.assertj.core.util.Files +import org.janelia.saalfeldlab.n5.N5KeyValueReader +import org.janelia.saalfeldlab.n5.N5KeyValueWriter +import org.janelia.saalfeldlab.n5.zarr.ZarrKeyValueReader +import org.janelia.saalfeldlab.n5.zarr.ZarrKeyValueWriter +import org.janelia.saalfeldlab.paintera.Paintera +import kotlin.test.Test +import kotlin.test.assertTrue + +class PainteraMainWindowTest { + + @Test + fun `project directory as n5 or zarr`() { + val chars : List = ('a'..'z') + ('A'..'Z') + ('0'..'9') + val randString = { List(10) { chars.random() }.joinToString("") } + + val noExtension = Files.temporaryFolder().resolve(randString()).absolutePath + assertTrue { Paintera.n5Factory.newWriter(noExtension) is N5KeyValueWriter } + assertTrue { Paintera.n5Factory.openReader(noExtension) is N5KeyValueReader } + + val noExtension2 = Files.temporaryFolder().resolve(randString()).absolutePath + assertTrue("no extension with zarr: should be zarr") { Paintera.n5Factory.newWriter("zarr:${noExtension2}") is ZarrKeyValueWriter } + assertTrue("No extension with .zgroup and no scheme should be zarr") { Paintera.n5Factory.openReader(noExtension2) is ZarrKeyValueReader } + + val nonsenseExtension = Files.temporaryFolder().resolve("${randString()}.asdf").absolutePath + assertTrue("random extension should be n5") { Paintera.n5Factory.newWriter(nonsenseExtension) is N5KeyValueWriter } + assertTrue("random extension should be n5") { Paintera.n5Factory.openReader(nonsenseExtension) is N5KeyValueReader } + + val nonsenseExtension2 = Files.temporaryFolder().resolve("${randString()}.asdf").absolutePath + assertTrue("random extension with zarr: should be zarr") { Paintera.n5Factory.newWriter("zarr:$nonsenseExtension2") is ZarrKeyValueWriter } + assertTrue("random extension with zarr: should be zarr") { Paintera.n5Factory.openReader(nonsenseExtension2) is ZarrKeyValueReader } + + val zarrFile = Files.temporaryFolder().resolve("${randString()}.zarr").absolutePath + assertTrue(".zarr should be zarr") { Paintera.n5Factory.newWriter(zarrFile) is ZarrKeyValueWriter } + assertTrue(".zarr should be zarr") { Paintera.n5Factory.openReader(zarrFile) is ZarrKeyValueReader } + + val n5File = Files.temporaryFolder().resolve("${randString()}.n5").absolutePath + assertTrue(".n5 should be n5") { Paintera.n5Factory.newWriter(n5File) is N5KeyValueWriter } + assertTrue(".n5 should be n5 ") { Paintera.n5Factory.openReader(n5File) is N5KeyValueReader } + } +} \ No newline at end of file