/*
 * Copyright (c) 2011-2015, Dan McNulty
 * All rights reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package net.udidb.engine.ops.impls.help;

import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Predicate;

import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;

import net.udidb.engine.context.DebuggeeContextAware;
import net.udidb.engine.ops.Operation;
import net.udidb.engine.ops.annotations.DisplayName;
import net.udidb.engine.ops.annotations.GlobalOperation;
import net.udidb.engine.ops.annotations.HelpMessage;
import net.udidb.engine.ops.annotations.LongHelpMessage;

/**
 * A class that provides access to help messages for operations
 *
 * @author mcnulty
 */
@Singleton
public class HelpMessageProvider {

    private static final String NEWLINE = System.lineSeparator();

    private final Map<String, HelpMessages> helpMessages = new TreeMap<>();

    private static class HelpMessages {
        public String shortMessage;

        public String longMessage;

        public boolean global;
    }

    @Inject
    public HelpMessageProvider(@Named("OP_PACKAGES") String[] opPackages) {
        Set<URL> packages = new HashSet<>();
        for (String opPackage : opPackages) {
            packages.addAll(ClasspathHelper.forPackage(opPackage));
        }
        Reflections reflections = new Reflections(packages, new SubTypesScanner());
        for (Class<? extends Operation> opClass : reflections.getSubTypesOf(Operation.class)) {
            if (Modifier.isAbstract(opClass.getModifiers())) continue;

            HelpMessage helpMessageAnnotation = opClass.getAnnotation(HelpMessage.class);
            DisplayName displayName = opClass.getAnnotation(DisplayName.class);
            LongHelpMessage longHelpMessageAnnotation = opClass.getAnnotation(LongHelpMessage.class);

            if (helpMessageAnnotation == null || displayName == null) {
                throw new RuntimeException(opClass.getSimpleName() + " is an invalid Operation");
            }

            String name = displayName.value();

            HelpMessages messages = new HelpMessages();
            messages.global = opClass.isAnnotationPresent(GlobalOperation.class);

            // TODO select message based on locale
            messages.shortMessage = helpMessageAnnotation.enMessage();

            if (longHelpMessageAnnotation == null) {
                messages.longMessage = "unspecified detailed help message";
            }else{
                // TODO select message based on locale
                messages.longMessage = longHelpMessageAnnotation.enMessage().replaceAll("\n", NEWLINE);
            }

            helpMessages.put(name, messages);
        }
    }

    /**
     * @param opName the Operation value
     * @return the short message; null if the operation is unknown
     */
    public String getShortMessage(String opName) {
        HelpMessages messages = helpMessages.get(opName);
        if ( messages != null ) {
            return messages.shortMessage;
        }

        return null;
    }

    /**
     * @param opName the Operation value
     * @return the long message; null if the operation is unknown
     */
    public String getLongMessage(String opName) {
        HelpMessages messages = helpMessages.get(opName);
        if ( messages != null ) {
            return messages.longMessage;
        }

        return null;
    }

    public String getGlobalLongMessage(String opName) {
         HelpMessages messages = helpMessages.get(opName);
        if ( messages != null ) {
            if (messages.global) {
                return messages.longMessage;
            }
        }

        return null;
    }

    /**
     * Appends the short message for all register operations, one per line
     *
     * @param builder the StringBuilder to append to
     */
    public void getAllShortMessages(StringBuilder builder) {
        getAllShortMessages(builder, e -> true);
    }

    private void getAllShortMessages(StringBuilder builder, Predicate<Map.Entry<String, HelpMessages>> predicate) {

        Iterator<Map.Entry<String, HelpMessages>> iter = helpMessages.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, HelpMessages> entry = iter.next();

            if (!predicate.test(entry)) {
                continue;
            }

            builder.append(entry.getKey()).append(" -- ").append(entry.getValue().shortMessage);

            if (iter.hasNext()) {
                builder.append(NEWLINE);
            }
        }
    }

    /**
     * Appends the short message for all registered, global-only operations, one per line
     *
     * @param builder the StringBuilder to append to
     */
    public void getAllGlobalShortMessages(StringBuilder builder) {
        getAllShortMessages(builder, e -> e.getValue().global);
    }
}

@@ -4551,17 +4551,43 @@
     
-Iterator%3C
+boolean first = true;%0A        for (
 Map.
@@ -4617,16 +4617,16 @@
 ges%3E
-%3E iter =
+ entry :
  hel
@@ -4649,160 +4649,180 @@
 et()
-.iterator();%0A        while (iter.hasNext()) %7B%0A            Map.Entry%3CString, HelpMessages%3E entry = iter.next();%0A%0A            if (!predicate.test(entry)) 
+) %7B%0A%0A            if (!predicate.test(entry)) %7B%0A                continue;%0A            %7D%0A%0A            if (!first) %7B%0A                builder.append(NEWLINE);%0A            %7Delse
 %7B%0A  
@@ -4827,39 +4827,44 @@
                 
-continu
+first = fals
 e;%0A            %7D
@@ -4965,98 +4965,8 @@
 ge);
-%0A%0A            if (iter.hasNext()) %7B%0A                builder.append(NEWLINE);%0A            %7D
 %0A   

Fix extra newline in filtered help messages