class ComponentGenerator {

    public Stream<FacetGenerator.InMemoryFile> create(final String tuple, final Build build, final String family,
            final String category, final Collection<ProjectRequest.SourceConfiguration> sources,
            final Collection<ProjectRequest.ProcessorConfiguration> processors,
            final Collection<ProjectRequest.ReusableConfiguration> configurations) {
        final String mainJava = build.getMainJavaDirectory() + '/' + tuple.replace('.', '/');
        final Map<String, Map<String, String>> messageProperties = new HashMap<>(); // Package , list of configuration
        // path for that package
        messageProperties.put(tuple, new TreeMap<>());
        if (family != null && !family.isEmpty()) {
            messageProperties.get(tuple).put(family + "._displayName", family);
        }

        final boolean hasService =
                (sources != null && !sources.isEmpty()) || (processors != null && !processors.isEmpty());
        if (!hasService) {
            return Stream.empty();
        }

        final String baseName = names.toJavaName(build.getArtifact());
        final String serviceName = baseName + "Service";
        final String usedFamily = ofNullable(family).orElse(build.getArtifact());
        final String iconResourcesDirectory = build.getMainResourcesDirectory() + "/icons";

        final Collection<FacetGenerator.InMemoryFile> files = new ArrayList<>();
        files
                .add(new FacetGenerator.InMemoryFile(mainJava + "/package-info.java",
                        tpl.render("generator/component/package-info.mustache", new HashMap<String, Object>() {

                            {
                                put("package", tuple);
                                put("family", usedFamily);
                                put("category", ofNullable(category).orElse(build.getArtifact()));
                                put("iconResources", iconResourcesDirectory);
                            }
                        })));
        files.add(generateIcon(iconResourcesDirectory, usedFamily));
        files
                .add(new FacetGenerator.InMemoryFile(mainJava + "/service/" + serviceName + ".java",
                        tpl.render("generator/component/Service.mustache", new HashMap<String, Object>() {

                            {
                                put("className", serviceName);
                                put("package", tuple + ".service");
                            }
                        })));

        configurations.stream().filter(it -> it.getType() != null && !it.getType().isEmpty()).forEach(it -> {
            final String lowerType = it.getType().toLowerCase(ENGLISH);
            final String configPck = tuple + '.' + lowerType;
            final String name = it.getName().substring(it.getName().lastIndexOf('.') + 1);
            generateConfiguration(configPck + '.' + name, configPck, mainJava, it.getStructure(), name, files,
                    lowerType);
            messageProperties
                    .computeIfAbsent(tuple, k -> new TreeMap<>())
                    .put(family + "." + lowerType + "." + name + "._displayName", name);
            if (it.getStructure() != null) {
                final Map<String, String> i18n = messageProperties.computeIfAbsent(configPck, k -> new TreeMap<>());
                toProperties(name, it.getStructure().getEntries())
                        .flatMap(this::toProperties)
                        .forEach(t -> i18n.put(t.key, t.value));
            }
        });

        if (sources != null && !sources.isEmpty()) {
            files
                    .addAll(createSourceFiles(tuple, iconResourcesDirectory, sources, mainJava, serviceName)
                            .collect(toList()));

            messageProperties.put(tuple + ".source", new TreeMap<String, String>() {

                {
                    putAll(sources
                            .stream()
                            .map(source -> new StringTuple2(family + "." + source.getName() + "._displayName",
                                    source.getName()))
                            .collect(toMap(StringTuple2::getKey, StringTuple2::getValue)));
                    putAll(sources
                            .stream()
                            .filter(source -> source.getConfiguration() != null
                                    && source.getConfiguration().getEntries() != null)
                            .flatMap(source -> toProperties(
                                    names.toConfigurationName(names.toMapperName(source.getName())),
                                    source.getConfiguration().getEntries()))
                            .flatMap(tuple3 -> toProperties(tuple3))
                            .collect(toMap(StringTuple2::getKey, StringTuple2::getValue, (k1, k2) -> k1)));
                }
            });
        }

        if (processors != null && !processors.isEmpty()) {
            files
                    .addAll(createProcessorFiles(tuple, iconResourcesDirectory, processors, mainJava, serviceName)
                            .collect(toList()));
            messageProperties.put(tuple + ".output", new TreeMap<String, String>() {

                {
                    putAll(processors
                            .stream()
                            .filter(ComponentGenerator::isOutput)
                            .map(processor -> new StringTuple2(family + "." + processor.getName() + "._displayName",
                                    processor.getName()))
                            .collect(toMap(StringTuple2::getKey, StringTuple2::getValue)));
                    putAll(processors
                            .stream()
                            .filter(processor -> processor.getConfiguration() != null
                                    && processor.getConfiguration().getEntries() != null)
                            .filter(ComponentGenerator::isOutput)
                            .flatMap(p -> toProperties(names.toConfigurationName(names.toProcessorName(p)),
                                    p.getConfiguration().getEntries()))
                            .flatMap(tuple3 -> toProperties(tuple3))
                            .collect(toMap(StringTuple2::getKey, StringTuple2::getValue, (k1, k2) -> k1)));
                }
            });

            messageProperties.put(tuple + ".processor", new TreeMap<String, String>() {

                {
                    putAll(processors
                            .stream()
                            .filter(ComponentGenerator::isProcessor)
                            .map(processor -> new StringTuple2(family + "." + processor.getName() + "._displayName",
                                    processor.getName()))
                            .collect(toMap(StringTuple2::getKey, StringTuple2::getValue)));
                    putAll(processors
                            .stream()
                            .filter(processor -> processor.getConfiguration() != null
                                    && processor.getConfiguration().getEntries() != null)
                            .filter(ComponentGenerator::isProcessor)
                            .flatMap(p -> toProperties(names.toConfigurationName(names.toProcessorName(p)),
                                    p.getConfiguration().getEntries()))
                            .flatMap(tuple3 -> toProperties(tuple3))
                            .collect(toMap(StringTuple2::getKey, StringTuple2::getValue, (k1, k2) -> k1)));
                }
            });
        }
        files.addAll(generateProperties(build.getMainResourcesDirectory(), messageProperties).collect(toList()));
        return files.stream();
    }

}