/*
 * JGrapes Event Driven Framework
 * Copyright (C) 2017-2018 Michael N. Lipp
 * 
 * This program is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Affero General Public License as published by 
 * the Free Software Foundation; either version 3 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License along 
 * with this program; if not, see <http://www.gnu.org/licenses/>.
 */

package org.jgrapes.core;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.function.Function;

/**
 * A component that collects all component factory services of 
 * a given type and creates an instance of each.
 * 
 * @param <F> the component factory type
 */
public class ComponentCollector<F extends ComponentFactory>
        extends Component {

    private static final List<Map<Object, Object>> SINGLE_DEFAULT
        = Arrays.asList(Collections.emptyMap());

    /**
     * Creates a new collector that collects the factories of the given 
     * type and uses each to create an instance with this component's
     * channel. Before the instance is created, the `matcher` 
     * function is invoked with the name of the class of the component
     * to be created as argument. The list of maps returned is
     * used to create components, passing each element in the list
     * as parameter to {@link ComponentFactory#create(Channel, Map)}
     * 
     * @param factoryClass the factory class
     * @param componentChannel this component's channel
     * @param matcher the matcher function
     */
    public ComponentCollector(
            Class<F> factoryClass, Channel componentChannel,
            Function<String, List<Map<Object, Object>>> matcher) {
        super(componentChannel);
        ServiceLoader<F> serviceLoader = ServiceLoader.load(factoryClass);
        for (F factory : serviceLoader) {
            List<Map<Object, Object>> configs = matcher.apply(
                factory.componentType().getName());
            for (Map<Object, Object> config : configs) {
                factory.create(channel(), config).ifPresent(
                    component -> attach(component));
            }
        }
    }

    /**
     * Utility constructor that uses each factory to create a single
     * instance, using an empty map as properties.
     * 
     * @param factoryClass the factory class
     * @param componentChannel this component's channel
     */
    public ComponentCollector(
            Class<F> factoryClass, Channel componentChannel) {
        this(factoryClass, componentChannel, type -> SINGLE_DEFAULT);
    }
}

@@ -1043,35 +1043,290 @@
 and 
-creates an instance of each
+uses each to create one or more components%0A * that are attached to the component collector instance.%0A * %0A * Effectively, the component collector leverages the %0A * mechanism provided by the service loader to determine%0A * the component tree that is built eventually at %0A * %22link time%22
 .%0A *
@@ -1694,18 +1694,27 @@
  create 
-an
+one or more
  instanc
@@ -1714,16 +1714,17 @@
 instance
+s
  with th
@@ -1722,24 +1722,32 @@
 s with this 
+%0A     * 
 component's%0A
@@ -1749,32 +1749,69 @@
 nt's
-%0A     * channel.
+ (the component collector's) channel. %0A     * %0A     *
  Before 
 the 
@@ -1810,20 +1810,16 @@
 ore 
-the 
 instance
  is 
@@ -1814,19 +1814,21 @@
 instance
- is
+s are
  created
@@ -1843,24 +1843,16 @@
 atcher%60 
-%0A     * 
 function
@@ -1855,16 +1855,24 @@
 tion is 
+%0A     * 
 invoked 
@@ -2045,16 +2045,16 @@
 he list%0A
-
      * a
@@ -2113,16 +2113,17 @@
 l, Map)%7D
+.
 %0A     * 

Improve documentation.