/*
 * Created on Apr 18, 2003
 */

package CH.ifa.draw.framework;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;

import de.renew.draw.storables.ontology.Drawing;
import de.renew.io.api.FileApi;
import de.renew.ioontology.ExtensionFileFilter;
import de.renew.ioontology.FileType;
import de.renew.plugin.PluginManager;


/**
 * This class creates and manages the drawing type manager.
 * @author Lawrence Cabac
 * @deprecated This class is not to be used externally. Please use the {@link de.renew.draw.storables.api.StorableApi} instead.
 */
@Deprecated(since = "5.0", forRemoval = true)
public final class DrawingTypeManager {
    /**
     * Logger instance for logging concerning the DrawingTypeManager.
     * @deprecated This field is not to be called externally anymore.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public static final org.apache.log4j.Logger LOGGER =
        org.apache.log4j.Logger.getLogger(DrawingTypeManager.class);
    private static DrawingTypeManager _dtm;
    private final Hashtable<String, ExtensionFileFilter> _drawingTypes;
    private ExtensionFileFilter _defaultFileFilter;
    private final Set<DrawingTypeManagerListener> _listeners;

    private DrawingTypeManager() {
        _drawingTypes = new Hashtable<>();
        _listeners = new HashSet<>();
    }

    /**
     * Creates an instance of DrawingTypeManager on the first call of the method.
     * @return created instance
     * @deprecated This method is not to be used externally. Please use {@link de.renew.draw.storables.ontology.DrawingChangeEvent} instead.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public static DrawingTypeManager getInstance() {
        //this should be made more save fix!
        //i.e. the existence of the Class should be checked 
        //and maybe whether this implements Diagram (possible?)
        if (_dtm == null) {
            _dtm = new DrawingTypeManager();
            ExtensionFileFilter ifa = FileApi.createExtensionFileFilter(FileType.DRAW);
            _dtm.register("CH.ifa.draw.standard.StandardDrawing", ifa);
            _dtm.setDefaultFileFilter(ifa);
            return _dtm;
        }
        return _dtm;
    }

    /**
     * Registers a new drawing type.
     * @param drawingName name of the drawing type
     * @param ff matching file filter for type
     * @return previous ff, if there was one before
     * @deprecated This method is not to be used externally.
     * Please use the method {@link de.renew.draw.storables.api.StorableApi#registerDrawingType(String, ExtensionFileFilter)} instead.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public Object register(String drawingName, ExtensionFileFilter ff) {
        LOGGER.debug("DrawingTypeManager: registering " + ff + " for drawing type " + drawingName);
        Object previous = _drawingTypes.put(drawingName, ff);
        for (DrawingTypeManagerListener drawingTypeManagerListener : _listeners) {
            drawingTypeManagerListener.typeRegistered(drawingName, ff);
        }

        return previous;
    }

    /**
     * Instantiates a Drawing based on its name.
     * @param name class name of drawing
     * @return drawing with given name, else null if no drawing can be found
     * @deprecated This method is not to be used externally.
     * Please use the method {@link de.renew.draw.storables.api.StorableApi#createDrawingForDrawingType(String)} instead.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public static Drawing getDrawingFromName(String name) {
        Drawing d = null;

        //LOGGER.debug("The name of the Drawing dtm "+name);
        try {
            ClassLoader classLoader = PluginManager.getInstance().getBottomClassLoader();
            Constructor<?> constructor = Class.forName(name, true, classLoader).getConstructor();
            d = (Drawing) constructor.newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        return d;
    }

    /**
     * Gets the Drawing associated with the given file filter.
     * @param ff given file filter
     * @deprecated This method is deprecated since it is not used anymore.
     * @return drawing, else null if no drawing can be found
     */
    @Deprecated(forRemoval = true)
    public static Drawing getDrawingForFilter(ExtensionFileFilter ff) {
        Hashtable<String, ExtensionFileFilter> hash = getInstance().getDrawingTypes();
        Enumeration<String> enumeration = hash.keys();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            ExtensionFileFilter fileFilter = hash.get(key);
            if (fileFilter.equals(ff)) {
                return getDrawingFromName(key);
            }
        }
        return null;
    }


    /**
     * Returns the mapping of drawing type names to their associated file filters.
     * @return drawing types
     * @deprecated This method is not to be used externally and will later be hidden.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public Hashtable<String, ExtensionFileFilter> getDrawingTypes() {
        return _drawingTypes;
    }

    /**
     * Checks whether the name of a DrawingType is included.
     * @param name name to be checked
     * @return boolean, {@code true} if key is contained
     * @deprecated This method is currently not used and will be removed in a later version.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public boolean contains(String name) {
        return _drawingTypes.containsKey(name);
    }

    /**
     * Gets the registered FileFilter for the DrawingType.
     * @param name name of drawing type
     * @return filter
     * @deprecated This method is not to be used externally.
     * Please use the method {@link de.renew.draw.storables.api.StorableApi#getExtensionFileFilterByDrawingType(String)} instead.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public ExtensionFileFilter getFilter(String name) {
        return _drawingTypes.get(name);
    }

    /**
     * Gets the default Filter.
     * @return default Filter
     * @deprecated This method is not to be used externally and will later be hidden.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public ExtensionFileFilter getDefaultFileFilter() {
        return _defaultFileFilter;
    }

    /**
     * Sets the default Filter.
     * @param filter filter to be set
     * @throws IllegalArgumentException the given file filter is unknown
     * @deprecated This method is not to be used externally and will later be hidden.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public void setDefaultFileFilter(ExtensionFileFilter filter) {
        if (!_drawingTypes.contains(filter)) {
            throw new IllegalArgumentException(
                "Cannot choose unknown drawing type as default: " + filter);
        }
        LOGGER.debug("DrawingTypeManager: choosing " + filter + " as default drawing type.");
        _defaultFileFilter = filter;
        for (DrawingTypeManagerListener drawingTypeManagerListener : _listeners) {
            drawingTypeManagerListener.defaultTypeChanged(filter);
        }
    }

    /**
     * Adds listener to the DrawingTypeManager.
     * @param listener listener to be added
     * @deprecated This method is not to be used externally and will later be hidden.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public void addListener(DrawingTypeManagerListener listener) {
        _listeners.add(listener);
    }

    /**
     * Removes listener from the DrawingTypeManager.
     * @param listener listener to remove
     * @deprecated This method is not to be used externally and will later be hidden.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public void removeListener(DrawingTypeManagerListener listener) {
        _listeners.remove(listener);
    }

    /**
     * Retracts a drawing type from the set of known types.
     * @param drawingName the name of the retracted drawing type
     * @deprecated This method is not to be used externally.
     * Please use the method {@link de.renew.draw.storables.api.StorableApi#unregisterDrawingType(String)} instead.
     */
    @Deprecated(since = "5.0", forRemoval = true)
    public void unregister(String drawingName) {
        LOGGER.debug("DrawingTypeManager: unregistering " + " for drawing type " + drawingName);
        _drawingTypes.remove(drawingName);
        if (drawingName.equals(_defaultFileFilter.getDescription())) {
            Enumeration<String> enu = _drawingTypes.keys();
            if (enu.hasMoreElements()) {
                ExtensionFileFilter ff = _drawingTypes.get(enu.nextElement());
                setDefaultFileFilter(ff);
            } else {
                _defaultFileFilter = null;
            }
        }

        for (DrawingTypeManagerListener drawingTypeManagerListener : _listeners) {
            drawingTypeManagerListener.defaultTypeChanged(_defaultFileFilter);
        }
    }
}