package de.renew.navigator.io.internal;

import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import de.renew.draw.storables.api.StorableApi;
import de.renew.draw.storables.ontology.Drawing;
import de.renew.io.api.FileApi;
import de.renew.ioontology.ExtensionFileFilter;
import de.renew.ioontology.FileFilter;
import de.renew.ioontology.FileFilterBuilder;
import de.renew.ioontology.MultiExtensionFileFilter;
import de.renew.ioontology.MultiExtensionFileFilterImpl;
import de.renew.ioontology.importing.ImportFormat;
import de.renew.ioontology.importing.ImportFormatMultiAbstract;

/**
 * Helper Class for handling file filters.
 * It uses both the file filters known to Renew as drawing types or import formats (accessed via the {@link StorableApi}),
 * as well as managing external types.
 * @author Konstantin Simon Maria Moellers
 * @version 2015-10-07
 */
public final class FileFilterHandler {

    private FileFilterHandler() {}

    /**
     * Creates a FileFilterBuilder object.
     * The functionality of the FileFilterBuilder is realized by using the methods {@link #buildFileFilter()}
     * and {@link #isExternallyOpenedFile(File)} of this type.
     * @return the created FileFilterBuilder
     */
    public static FileFilterBuilder createFileFilterBuilder() {
        return new FileFilterBuilder() {
            @Override
            public FileFilter buildFileFilter() {
                return FileFilterHandler.buildFileFilter();
            }

            @Override
            public boolean isExternallyOpenedFile(File file) {
                return FileFilterHandler.isExternallyOpenedFile(file);
            }
        };
    }

    /**
     * Creates a file filter for IO operations by combining all file filters known to Renew
     * through drawing types and import formats (accessed via the {@link StorableApi})
     * with known external file types that are held by this class.
     *
     * @return The file filter instance.
     */
    public static FileFilter buildFileFilter() {
        final MultiExtensionFileFilter fileFilter = StorableApi.getKnownDrawingTypesFileFilter();

        List<ImportFormat<Drawing>> formats = StorableApi.getImportFormats();
        for (ImportFormat<Drawing> format : formats) {
            // Add a single import format.
            addImportFormat(fileFilter, format);
        }

        // Add file filters of external file types.
        fileFilter.addAll(getExternalFileTypes());

        return fileFilter;
    }

    /**
     * Finds out if a file should be opened externally.
     *
     * @param file the file to check
     * @return {@code true}, if the file should be opened externally
     */
    public static boolean isExternallyOpenedFile(File file) {
        MultiExtensionFileFilter fileFilter =
            new MultiExtensionFileFilterImpl("temp", getExternalFileTypes());
        return fileFilter.accept(file);
    }


    /**
     * Adds an import format to the accepted file types of the navigator.
     *
     * @param format import format to add
     * @param target target to add the import format to
     */
    private static void addImportFormat(
        MultiExtensionFileFilter target, ImportFormat<Drawing> format)
    {
        // Load each format of a multi format.
        if (format instanceof ImportFormatMultiAbstract<Drawing> multiFormat) {
            List<ImportFormat<Drawing>> allImportFormats = multiFormat.getImportFormats();
            for (ImportFormat<Drawing> importFormat : allImportFormats) {
                addImportFormat(target, importFormat);
            }
            return;
        }

        // Load an extension file filter.
        if (format.fileFilter() instanceof ExtensionFileFilter) {
            target.add((ExtensionFileFilter) format.fileFilter());
            return;
        }

        throw new RuntimeException(
            String.format("Unsupported import format: %s", format.getClass()));
    }

    /**
     * This method returns a collection of all file filters that are opened externally.
     *
     * @return collection of all file filters which are opened externally
     */
    private static Collection<ExtensionFileFilter> getExternalFileTypes() {
        return Arrays.asList(
            FileApi.createExtensionFileFilter("kb", "Knowledge Base"),
            FileApi.createExtensionFileFilter("java", "Java Sourcecode"),
            FileApi.createExtensionFileFilter("jsp", "Java Servlet Pages"),
            FileApi.createExtensionFileFilter("xml", "Extensible Markup Language"),
            FileApi.createExtensionFileFilter("xmi", "XML Metadata Interchange"),
            FileApi.createExtensionFileFilter("md", "Markdown"),
            FileApi.createExtensionFileFilter("tex", "LaTeX file"),
            FileApi.createExtensionFileFilter("html", "Hypertext"),
            FileApi.createExtensionFileFilter("cfg", "Configuration"),
            FileApi.createExtensionFileFilter("gif", "Graphics Interchange Format"),
            FileApi.createExtensionFileFilter("png", "Portable Network Graphics"),
            FileApi.createExtensionFileFilter("jpg", "Joint Photographic experts Group"),
            FileApi.createExtensionFileFilter("jpeg", "Joint Photographic Experts Group"));
    }
}