/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.camel.k.listener;

import java.util.Arrays;
import java.util.Comparator;

import org.apache.camel.k.Runtime;
import org.apache.camel.k.SourceDefinition;
import org.apache.camel.k.SourceType;
import org.apache.camel.k.support.Constants;
import org.apache.camel.k.support.PropertiesSupport;
import org.apache.camel.k.support.SourcesSupport;
import org.apache.camel.spi.Configurer;
import org.apache.camel.util.ObjectHelper;

@Configurer
public class SourcesConfigurer extends AbstractPhaseListener {

    public static final String CAMEL_K_PREFIX = "camel.k.";
    public static final String CAMEL_K_SOURCES_PREFIX = "camel.k.sources[";

    private SourceDefinition[] sources;

    public SourcesConfigurer() {
        super(Runtime.Phase.ConfigureRoutes);
    }

    public SourceDefinition[] getSources() {
        return sources;
    }

    public void setSources(SourceDefinition[] sources) {
        this.sources = sources;
    }

    @Override
    protected void accept(Runtime runtime) {
        //
        // load routes from env var for backward compatibility
        //
        String routes = System.getProperty(Constants.PROPERTY_CAMEL_K_ROUTES);
        if (ObjectHelper.isEmpty(routes)) {
            routes = System.getenv(Constants.ENV_CAMEL_K_ROUTES);
        }

        if (ObjectHelper.isNotEmpty(routes)) {
            SourcesSupport.loadSources(runtime, routes.split(","));
        }

        //
        // load routes from properties
        //
        // In order not to load any unwanted property, the filer remove any
        // property that can't be bound to this configurer.
        //
        PropertiesSupport.bindProperties(
                runtime.getCamelContext(),
                this,
                k -> k.startsWith(CAMEL_K_SOURCES_PREFIX),
                CAMEL_K_PREFIX);

        checkUniqueErrorHandler();
        sortSources();

        if (ObjectHelper.isNotEmpty(this.getSources())) {
            SourcesSupport.loadSources(runtime, this.getSources());
        }
    }

    private void checkUniqueErrorHandler() {
        checkUniqueErrorHandler(this.sources);
    }

    static void checkUniqueErrorHandler(SourceDefinition[] sources) {
        long errorHandlers = sources == null ? 0 : Arrays.stream(sources).filter(s -> s.getType() == SourceType.errorHandler).count();
        if (errorHandlers > 1) {
            throw new IllegalArgumentException("Expected only one error handler source type, got " + errorHandlers);
        }
    }

    private void sortSources() {
        sortSources(this.getSources());
    }

    static void sortSources(SourceDefinition[] sources) {
        if (sources == null) {
            return;
        }
        // We must ensure the source order as defined in SourceType enum
        Arrays.sort(sources, Comparator.comparingInt(a -> a.getType().ordinal()));
    }

}
