package CH.ifa.draw.io.importFormats;

import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import javax.swing.filechooser.FileFilter;

import CH.ifa.draw.IOHelper;
import CH.ifa.draw.io.CombinationFileFilter;
import CH.ifa.draw.io.SimpleFileFilter;
import de.renew.draw.storables.ontology.Drawing;
import de.renew.ioontology.ExtensionFileFilter;
import de.renew.ioontology.MultiExtensionFileFilter;
import de.renew.ioontology.MultiExtensionFileFilterImpl;

/**
 * Abstract implementation of ImportFormatMulti and extension of the class ImportFormatAbstract.
 * @deprecated This type is not to be used anymore. Please use {@link de.renew.ioontology.importing.ImportFormatMultiAbstract} and its subtypes instead.
 */
@Deprecated(since = "5.0", forRemoval = true)
@SuppressWarnings("removal")
public abstract class ImportFormatMultiAbstract extends ImportFormatAbstract
    implements ImportFormatMulti
{
    // Attributes
    // All ImportFormats that have been added (MultiFormats do count as one element).
    private List<ImportFormat> _formats;

    /**
     * Constructs ImportFormatMultiAbstract with a given format name and a new file filter.
     * @param name The given format name
     * @param filterName The name of the new file filter
     */
    public ImportFormatMultiAbstract(String name, String filterName) {
        super(name, new MultiExtensionFileFilterImpl(filterName));
        setFormats(new LinkedList<ImportFormat>());
    }

    // Methods


    /**
     * List of all added ImportFormats.
     * @ensure result != null
     * @return The list of added import formats
     */
    protected List<ImportFormat> formats() {
        List<ImportFormat> result = null;
        result = _formats;
        assert (result != null) : "Failure in ImportFormatAbstract: result == null";
        return result;
    }

    /**
     * Sets _formats to formats.
     * @require formats != null
     * @ensure formats() != null
     * @ensure formats().equals(formats)
     * @param formats the value to be set.
     */
    protected void setFormats(List<ImportFormat> formats) {
        _formats = formats;
        assert (formats() != null) : "Failure in ImportFormatAbstract: formats() == null";
        assert (formats().equals(formats))
            : "Failure in ImportFormatAbstract: formats() != formats";
    }

    /**
     * Returns a MultiExtensionFileFilter that contains all added FileFilters
     * (Does not contain other MultiExtensionFileFilter but their elements).
     * @ensure result != null.
     * @return the MultiExtensionFileFilter for the ImportFormat.
     */
    protected MultiExtensionFileFilter multiFileFilter() {
        MultiExtensionFileFilter result = (MultiExtensionFileFilter) fileFilter();
        Objects.requireNonNull(result, "Failure in ImportFormatAbstract: result == null");
        return result;
    }

    /**
     * Adds a fileFilter to the CombinationFileFilter (If the fileFilter itself is a
     * CombinationFileFilter only its elements are added).
     * @require fileFilter != null.
     * @param fileFilter the FileFilter to be added.
     */
    protected void addFileFilter(FileFilter fileFilter) {
        if (fileFilter instanceof CombinationFileFilter comFileFilter) {
            Iterator<SimpleFileFilter> filters = comFileFilter.getFileFilters().iterator();
            while (filters.hasNext()) {
                FileFilter element = filters.next();
                addFileFilter(element);
            }
        } else if (fileFilter instanceof MultiExtensionFileFilter multiFilter) {
            for (ExtensionFileFilter filter : multiFilter.getFileFilters()) {
                if (filter instanceof FileFilter ff) {
                    addFileFilter(ff);
                } else {
                    addFileFilter(IOHelper.mapToSwingFileFilter(filter));
                }
            }
        } else {
            if (fileFilter instanceof ExtensionFileFilter) {
                multiFileFilter().add((ExtensionFileFilter) fileFilter);
            }
        }
    }

    /**
     * Removes the fileFilter from the CombinationFileFilter (If fileFilter is
     * a CombinationFileFiler all its elements are removed).
     * @require fileFilter != null.
     * @param fileFilter FileFilter to be removed.
     */
    protected void removeFileFilter(FileFilter fileFilter) {
        if (fileFilter instanceof CombinationFileFilter comFileFilter) {
            Iterator<SimpleFileFilter> filters = comFileFilter.getFileFilters().iterator();
            while (filters.hasNext()) {
                FileFilter element = filters.next();
                removeFileFilter(element);
            }
        } else if (fileFilter instanceof MultiExtensionFileFilter multiFilter) {
            for (ExtensionFileFilter filter : multiFilter.getFileFilters()) {
                if (filter instanceof FileFilter ff) {
                    removeFileFilter(ff);
                } else {
                    removeFileFilter(IOHelper.mapToSwingFileFilter(filter));
                }
            }
        } else {
            if (fileFilter instanceof ExtensionFileFilter) {
                multiFileFilter().remove((ExtensionFileFilter) fileFilter);
            }
        }
    }

    // ---------------------------------------------------------------------
    // Implementation of the ImportFormatMulti Interface
    // ---------------------------------------------------------------------


    /**
     * @see ImportFormatMulti#addImportFormat(ImportFormat)
     */
    @Override
    public void addImportFormat(ImportFormat format) {
        formats().add(format);
        FileFilter filter = format.fileFilter();
        addFileFilter(filter);
    }

    /**
     * @see ImportFormatMulti#allImportFormats()
     */
    @Override
    public ImportFormat[] allImportFormats() {
        ImportFormat[] result = null;
        result = new ImportFormat[formats().size()];
        for (int pos = 0; pos < result.length; pos++) {
            result[pos] = formats().get(pos);
        }
        assert (result != null) : "Failure in ImportFormatAbstract: result == null";
        return result;
    }

    /**
     * @see ImportFormatMulti#removeImportFormat(ImportFormat)
     */
    @Override
    public void removeImportFormat(ImportFormat format) {
        removeFileFilter(format.fileFilter());
        formats().remove(format);
    }

    /**
      * @see ImportFormat#importFiles(URL[])
     */
    @Override
    public List<Drawing> importFiles(URL[] paths) throws Exception {
        List<Drawing> result = new ArrayList<Drawing>();
        for (int posfiles = 0; posfiles < paths.length; posfiles++) {
            ImportFormat[] formats = allImportFormats();
            for (int posformat = 0; posformat < formats.length; posformat++) {
                if (formats[posformat].canImport(paths[posfiles])) {
                    URL[] a = new URL[1];
                    a[0] = paths[posfiles];
                    result.addAll(formats[posformat].importFiles(a));
                }
            }
        }
        return result;
    }
}