package de.renew.ioontology.exporting;

import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

import CH.ifa.draw.io.CombinationFileFilter;
import de.renew.ioontology.ExtensionFileFilter;
import de.renew.ioontology.FileFilter;
import de.renew.ioontology.MultiExtensionFileFilter;
import de.renew.ioontology.MultiExtensionFileFilterImpl;

/**
 * Abstract implementation of ExportFormatMulti and extension of the class ExportFormatAbstract.
 * @param <T> the type of the Object that is exported
 */
public abstract class ExportFormatMultiAbstract<T> extends ExportFormatAbstract<T>
    implements ExportFormatMulti<T>
{
    // All ExportFormats that have been added (MultiFormats do count as one element).
    private final List<ExportFormat<T>> _formats;

    /**
     * Constructs ExportFormatAbstract with a given name and a name for the new {@link MultiExtensionFileFilter}.
     * @param name the given name
     * @param filterName the name for the new combination file filter
     */
    public ExportFormatMultiAbstract(String name, String filterName) {
        super(name, new MultiExtensionFileFilterImpl(filterName));
        _formats = new LinkedList<>();
    }

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

    /**
     * Adds a fileFilter to the CombinationFileFilter (If the fileFilter itself is a
     * CombinationFileFilter, only its elements are added).
     * @param fileFilter the fileFilter to be added
     */
    private void addFileFilter(FileFilter fileFilter) {
        if (fileFilter instanceof CombinationFileFilter comFileFilter) {
            for (FileFilter element : comFileFilter.getFileFilters()) {
                addFileFilter(element);
            }
        } else if (fileFilter instanceof MultiExtensionFileFilter multiFilter) {
            for (ExtensionFileFilter filter : multiFilter.getFileFilters()) {
                addFileFilter(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).
     * @param fileFilter fileFilter to be removed.
     */
    private void removeFileFilter(FileFilter fileFilter) {
        if (fileFilter instanceof CombinationFileFilter comFileFilter) {
            for (FileFilter element : comFileFilter.getFileFilters()) {
                removeFileFilter(element);
            }
        } else if (fileFilter instanceof MultiExtensionFileFilter multiFilter) {
            for (ExtensionFileFilter filter : multiFilter.getFileFilters()) {
                removeFileFilter(filter);
            }
        } else {
            if (fileFilter instanceof ExtensionFileFilter) {
                multiFileFilter().remove((ExtensionFileFilter) fileFilter);
            }
        }
    }

    // ---------------------------------------------------------------------
    // Implementation of the ExportFormatMulti Interface
    // ---------------------------------------------------------------------

    @Override
    public void addExportFormat(ExportFormat<T> format) {
        _formats.add(format);
        addFileFilter(format.fileFilter());
    }

    @Override
    public List<ExportFormat<T>> getExportFormats() {
        return _formats;
    }

    @Override
    public void removeExportFormat(ExportFormat<T> format) {
        removeFileFilter(format.fileFilter());
        _formats.remove(format);
    }


    @Override
    public boolean canExportNto1() {
        return false;
    }

    @Override
    public ExportFormat<T>[] canExport(File path) {
        ExportFormat<T>[] result = super.canExport(path);
        if (path != null) {
            List<ExportFormat<T>[]> list = new LinkedList<>();
            int count = 0;
            for (int pos = 0; pos < getExportFormats().size(); pos++) {
                ExportFormat<T>[] formats = getExportFormats().get(pos).canExport(path);
                if (formats.length > 0) {
                    list.add(formats);
                    count = count + formats.length;
                }
            }
            result = new ExportFormat[count];
            for (ExportFormat<T>[] element : list) {
                for (ExportFormat<T> exportFormat : element) {
                    result[--count] = exportFormat;
                }
            }
        }
        Objects.requireNonNull(result, "Failure in ExportFormatMultiAbstract: result == null");
        return result;
    }
}