package de.renew.console.completer;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import jline.console.completer.Completer;
import jline.console.completer.NullCompleter;
import jline.console.completer.StringsCompleter;

import de.renew.console.CHDependencyListener;
import de.renew.plugin.IPlugin;


/**
 * The DrawingsCompleter class implements the Completer interface and
 * provides auto-completion suggestions for drawing names retrieved dynamically
 * from an external CH plugin using reflection. If no drawings are available,
 * it falls back to a NullCompleter that provides no suggestions.
 * @author cabac
 *
 */
public class DrawingsCompleter implements Completer {
    private static final org.apache.log4j.Logger LOGGER =
        org.apache.log4j.Logger.getLogger(DrawingsCompleter.class);

    private final NullCompleter _nullCompleter;

    /**
     * Constructs a new instance of the DrawingsCompleter.
     * This constructor initializes the DrawingsCompleter and creates a new instance of NullCompleter.
     */
    public DrawingsCompleter() {
        this._nullCompleter = new NullCompleter();
    }

    @Override
    public int complete(String buffer, int cursor, List<CharSequence> candidates) {
        List<String> drawingNames = getDrawingNames();
        if (CHDependencyListener.getChPlugin() != null && !drawingNames.isEmpty()) {
            return new StringsCompleter(drawingNames).complete(buffer, cursor, candidates);
        }
        return this._nullCompleter.complete(buffer, cursor, candidates);
    }

    /**
     * Retrieves a list of drawing names from the CH plugin, if available.
     * <p>
     * This method uses reflection to call methods on the CH plugin and retrieve
     * drawing names without needing a direct dependency. If the CH plugin or the
     * required methods are unavailable, it logs a debug message.
     * </p>
     *
     * @return a {@code List} containing the names of all available drawings,
     *         or an empty list if no drawings are found or accessible
     */
    private static List<String> getDrawingNames() {
        List<String> drawingNames = new ArrayList<>();
        try {
            Class<? extends IPlugin> drawPluginClass =
                CHDependencyListener.getChPlugin().getClass();
            Method getGuiMethod = drawPluginClass.getMethod("getGui");
            Object gui = getGuiMethod.invoke(CHDependencyListener.getChPlugin());

            if (gui != null) {
                Method drawingsMethod = gui.getClass().getMethod("drawings");
                Enumeration<?> drawings = (Enumeration<?>) drawingsMethod.invoke(gui);

                while (drawings.hasMoreElements()) {
                    Object drawing = drawings.nextElement();
                    Method getNameMethod = drawing.getClass().getMethod("getName");
                    String name = (String) getNameMethod.invoke(drawing);
                    drawingNames.add(name);
                }
            }
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            LOGGER.debug(
                "Could not get the list of drawing names, although the "
                    + "CH plugin should be available.",
                e);
        }
        return drawingNames;
    }
}