/*
 * 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.sling.event.impl.jobs;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.discovery.PropertyProvider;
import org.apache.sling.event.impl.jobs.config.TopologyCapabilities;
import org.apache.sling.event.impl.support.TopicMatcher;
import org.apache.sling.event.impl.support.TopicMatcherHelper;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
import org.apache.sling.event.jobs.consumer.JobConsumer.JobResult;
import org.apache.sling.event.jobs.consumer.JobExecutionContext;
import org.apache.sling.event.jobs.consumer.JobExecutionResult;
import org.apache.sling.event.jobs.consumer.JobExecutor;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This component manages/keeps track of all job consumer services.
 */
@Component(service = JobConsumerManager.class,
    property = {
          Constants.SERVICE_VENDOR + "=The Apache Software Foundation"
    })
@Designate(ocd = JobConsumerManager.Config.class)
public class JobConsumerManager {

    @ObjectClassDefinition(name = "Apache Sling Job Consumer Manager",
           description="The consumer manager controls the job consumer (= processors). "
                     + "It can be used to temporarily disable job processing on the current instance. Other instances "
                     + "in a cluster are not affected.")
    public @interface Config {

        @AttributeDefinition(name = "Distribute config",
          description="If this is disabled, the configuration is not persisted on save in the cluster and is "
                    + "only used on the current instance. This option should always be disabled!")
        boolean org_apache_sling_installer_configuration_persist() default false;

        @AttributeDefinition(name = "Topic Whitelist",
              description="This is a list of topics which currently should be "
                        + "processed by this instance. Leaving it empty, all job consumers are disabled. Putting a '*' as "
                        + "one entry, enables all job consumers. Adding separate topics enables job consumers for exactly "
                        + "this topic.")
        String[] job_consumermanager_whitelist() default "*";

        @AttributeDefinition(name = "Topic Blacklist",
              description="This is a list of topics which currently shouldn't be "
                        + "processed by this instance. Leaving it empty, all job consumers are enabled. Putting a '*' as "
                        + "one entry, disables all job consumers. Adding separate topics disables job consumers for exactly "
                        + "this topic.")
        String[] job_consumermanager_blacklist();
    }

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /** The map with the consumers, keyed by topic, sorted by service ranking. */
    private final Map<String, List<ConsumerInfo>> topicToConsumerMap = new HashMap<>();

    /** ServiceRegistration for propagation. */
    private ServiceRegistration<PropertyProvider> propagationService;

    private String topics;

    private TopicMatcher[] whitelistMatchers;

    private TopicMatcher[] blacklistMatchers;

    private volatile long changeCount;

    private BundleContext bundleContext;

    private final Map<String, Object[]> listenerMap = new HashMap<>();

    private Dictionary<String, Object> getRegistrationProperties() {
        final Dictionary<String, Object> serviceProps = new Hashtable<>();
        serviceProps.put(PropertyProvider.PROPERTY_PROPERTIES, TopologyCapabilities.PROPERTY_TOPICS);
        // we add a changing property to the service registration
        // to make sure a modification event is really sent
        synchronized ( this ) {
            serviceProps.put("changeCount", this.changeCount++);
        }
        return serviceProps;
    }

    @Activate
    protected void activate(final BundleContext bc, final Config config) {
        this.bundleContext = bc;
        this.modified(bc, config);
    }

    @Modified
    protected void modified(final BundleContext bc, final Config config) {
        final boolean wasEnabled = this.propagationService != null;
        this.whitelistMatchers = TopicMatcherHelper.buildMatchers(config.job_consumermanager_whitelist());
        this.blacklistMatchers = TopicMatcherHelper.buildMatchers(config.job_consumermanager_blacklist());

        final boolean enable = this.whitelistMatchers != null && this.blacklistMatchers != TopicMatcherHelper.MATCH_ALL;
        if ( wasEnabled != enable ) {
            synchronized ( this.topicToConsumerMap ) {
                this.calculateTopics(enable);
            }
            if ( enable ) {
                logger.debug("Registering property provider with: {}", this.topics);
                this.propagationService = bc.registerService(PropertyProvider.class,
                        new PropertyProvider() {

                            @Override
                            public String getProperty(final String name) {
                                if ( TopologyCapabilities.PROPERTY_TOPICS.equals(name) ) {
                                    return topics;
                                }
                                return null;
                            }
                        }, this.getRegistrationProperties());
            } else {
                logger.debug("Unregistering property provider with");
                this.propagationService.unregister();
                this.propagationService = null;
            }
        } else if ( enable ) {
            // update properties
            synchronized ( this.topicToConsumerMap ) {
                this.calculateTopics(true);
            }
            logger.debug("Updating property provider with: {}", this.topics);
            this.propagationService.setProperties(this.getRegistrationProperties());
        }
    }

    @Deactivate
    protected void deactivate() {
        if ( this.propagationService != null ) {
            this.propagationService.unregister();
            this.propagationService = null;
        }
        this.bundleContext = null;
        synchronized ( this.topicToConsumerMap ) {
            this.topicToConsumerMap.clear();
            this.listenerMap.clear();
        }
    }

    /**
     * Get the executor for the topic.
     * @param topic The job topic
     * @return A consumer or <code>null</code>
     */
    public JobExecutor getExecutor(final String topic) {
        synchronized ( this.topicToConsumerMap ) {
            final List<ConsumerInfo> consumers = this.topicToConsumerMap.get(topic);
            if ( consumers != null ) {
                return consumers.get(0).getExecutor(this.bundleContext);
            }
            int pos = topic.lastIndexOf('/');
            if ( pos > 0 ) {
                final String category = topic.substring(0, pos + 1).concat("*");
                final List<ConsumerInfo> categoryConsumers = this.topicToConsumerMap.get(category);
                if ( categoryConsumers != null ) {
                    return categoryConsumers.get(0).getExecutor(this.bundleContext);
                }

                // search deep consumers (since 1.2 of the consumer package)
                do {
                    final String subCategory = topic.substring(0, pos + 1).concat("**");
                    final List<ConsumerInfo> subCategoryConsumers = this.topicToConsumerMap.get(subCategory);
                    if ( subCategoryConsumers != null ) {
                        return subCategoryConsumers.get(0).getExecutor(this.bundleContext);
                    }
                    pos = topic.lastIndexOf('/', pos - 1);
                } while ( pos > 0 );
            }
        }
        return null;
    }

    public void registerListener(final String key, final JobExecutor consumer, final JobExecutionContext handler) {
        synchronized ( this.topicToConsumerMap ) {
            this.listenerMap.put(key, new Object[] {consumer, handler});
        }
    }

    public void unregisterListener(final String key) {
        synchronized ( this.topicToConsumerMap ) {
            this.listenerMap.remove(key);
        }
    }

    /**
     * Return the topics information of this instance.
     */
    public String getTopics() {
        return this.topics;
    }

    /**
     * Bind a new consumer
     * @param serviceReference The service reference to the consumer.
     */
    @Reference(service=JobConsumer.class,
            cardinality=ReferenceCardinality.MULTIPLE,
            policy=ReferencePolicy.DYNAMIC)
    protected void bindJobConsumer(final ServiceReference<JobConsumer> serviceReference) {
        this.bindService(serviceReference, true);
    }

    /**
     * Unbind a consumer
     * @param serviceReference The service reference to the consumer.
     */
    protected void unbindJobConsumer(final ServiceReference<JobConsumer> serviceReference) {
        this.unbindService(serviceReference, true);
    }

    /**
     * Bind a new executor
     * @param serviceReference The service reference to the executor.
     */
    @Reference(service=JobExecutor.class,
            cardinality=ReferenceCardinality.MULTIPLE,
            policy=ReferencePolicy.DYNAMIC)
    protected void bindJobExecutor(final ServiceReference<JobExecutor> serviceReference) {
        this.bindService(serviceReference, false);
    }

    /**
     * Unbind a executor
     * @param serviceReference The service reference to the executor.
     */
    protected void unbindJobExecutor(final ServiceReference<JobExecutor> serviceReference) {
        this.unbindService(serviceReference, false);
    }

    /**
     * Bind a consumer or executor
     * @param serviceReference The service reference to the consumer or executor.
     * @param isConsumer Indicating whether this is a JobConsumer or JobExecutor
     */
    private void bindService(final ServiceReference<?> serviceReference, final boolean isConsumer) {
        final String[] topics = PropertiesUtil.toStringArray(serviceReference.getProperty(JobConsumer.PROPERTY_TOPICS));
        if ( topics != null && topics.length > 0 ) {
            final ConsumerInfo info = new ConsumerInfo(serviceReference, isConsumer);
            boolean changed = false;
            synchronized ( this.topicToConsumerMap ) {
                for(final String t : topics) {
                    if ( t != null ) {
                        final String topic = t.trim();
                        if ( topic.length() > 0 ) {
                            List<ConsumerInfo> consumers = this.topicToConsumerMap.get(topic);
                            if ( consumers == null ) {
                                consumers = new ArrayList<>();
                                this.topicToConsumerMap.put(topic, consumers);
                                changed = true;
                            }
                            consumers.add(info);
                            Collections.sort(consumers);
                        }
                    }
                }
                if ( changed ) {
                    this.calculateTopics(this.propagationService != null);
                }
            }
            if ( changed && this.propagationService != null ) {
                logger.debug("Updating property provider with: {}", this.topics);
                this.propagationService.setProperties(this.getRegistrationProperties());
            }
        }
    }

    /**
     * Unbind a consumer or executor
     * @param serviceReference The service reference to the consumer or executor.
     * @param isConsumer Indicating whether this is a JobConsumer or JobExecutor
     */
    private void unbindService(final ServiceReference<?> serviceReference, final boolean isConsumer) {
        final String[] topics = PropertiesUtil.toStringArray(serviceReference.getProperty(JobConsumer.PROPERTY_TOPICS));
        if ( topics != null && topics.length > 0 ) {
            final ConsumerInfo info = new ConsumerInfo(serviceReference, isConsumer);
            boolean changed = false;
            synchronized ( this.topicToConsumerMap ) {
                for(final String t : topics) {
                    if ( t != null ) {
                        final String topic = t.trim();
                        if ( topic.length() > 0 ) {
                            final List<ConsumerInfo> consumers = this.topicToConsumerMap.get(topic);
                            if ( consumers != null ) { // sanity check
                                for(final ConsumerInfo oldConsumer : consumers) {
                                    if ( oldConsumer.equals(info) && oldConsumer.executor != null ) {
                                        // notify listener
                                        for(final Object[] listenerObjects : this.listenerMap.values()) {
                                            if ( listenerObjects[0] == oldConsumer.executor ) {
                                                final JobExecutionContext context = (JobExecutionContext)listenerObjects[1];
                                                context.asyncProcessingFinished(context.result().failed());
                                                break;
                                            }
                                        }
                                    }
                                }
                                consumers.remove(info);
                                if ( consumers.size() == 0 ) {
                                    this.topicToConsumerMap.remove(topic);
                                    changed = true;
                                }
                            }
                        }
                    }
                }
                if ( changed ) {
                    this.calculateTopics(this.propagationService != null);
                }
            }
            if ( changed && this.propagationService != null ) {
                logger.debug("Updating property provider with: {}", this.topics);
                this.propagationService.setProperties(this.getRegistrationProperties());
            }
        }
    }

    private boolean match(final String topic, final TopicMatcher[] matchers) {
        for(final TopicMatcher m : matchers) {
            if ( m.match(topic) != null ) {
                return true;
            }
        }
        return false;
    }

    private void calculateTopics(final boolean enabled) {
        if ( enabled ) {
            // create a sorted list - this ensures that the property value
            // is always the same for the same topics.
            final List<String> topicList = new ArrayList<>();
            for(final String topic : this.topicToConsumerMap.keySet() ) {
                // check whitelist
                if ( this.match(topic, this.whitelistMatchers) ) {
                    // and blacklist
                    if ( this.blacklistMatchers == null || !this.match(topic, this.blacklistMatchers) ) {
                        topicList.add(topic);
                    }
                }
            }
            Collections.sort(topicList);

            final StringBuilder sb = new StringBuilder();
            boolean first = true;
            for(final String topic : topicList ) {
                if ( first ) {
                    first = false;
                } else {
                    sb.append(',');
                }
                sb.append(topic);
            }
            this.topics = sb.toString();
        } else {
            this.topics = null;
        }
    }

    /**
     * Internal class caching some consumer infos like service id and ranking.
     */
    private final static class ConsumerInfo implements Comparable<ConsumerInfo> {

        public final ServiceReference<?> serviceReference;
        private final boolean isConsumer;
        public JobExecutor executor;
        public final int ranking;
        public final long serviceId;

        public ConsumerInfo(final ServiceReference<?> serviceReference, final boolean isConsumer) {
            this.serviceReference = serviceReference;
            this.isConsumer = isConsumer;
            final Object sr = serviceReference.getProperty(Constants.SERVICE_RANKING);
            if ( sr == null || !(sr instanceof Integer)) {
                this.ranking = 0;
            } else {
                this.ranking = (Integer)sr;
            }
            this.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID);
        }

        @Override
        public int compareTo(final ConsumerInfo o) {
            if ( this.ranking < o.ranking ) {
                return 1;
            } else if (this.ranking > o.ranking ) {
                return -1;
            }
            // If ranks are equal, then sort by service id in descending order.
            return (this.serviceId < o.serviceId) ? -1 : 1;
        }

        @Override
        public boolean equals(final Object obj) {
            if ( obj instanceof ConsumerInfo ) {
                return ((ConsumerInfo)obj).serviceId == this.serviceId;
            }
            return false;
        }

        @Override
        public int hashCode() {
            return serviceReference.hashCode();
        }

        public JobExecutor getExecutor(final BundleContext bundleContext) {
            if ( executor == null ) {
                if ( this.isConsumer ) {
                    executor = new JobConsumerWrapper((JobConsumer) bundleContext.getService(this.serviceReference));
                } else {
                    executor = (JobExecutor) bundleContext.getService(this.serviceReference);
                }
            }
            return executor;
        }
    }

    private final static class JobConsumerWrapper implements JobExecutor {

        private final JobConsumer consumer;

        public JobConsumerWrapper(final JobConsumer consumer) {
            this.consumer = consumer;
        }

        @Override
        public JobExecutionResult process(final Job job, final JobExecutionContext context) {
            final JobConsumer.AsyncHandler asyncHandler =
                    new JobConsumer.AsyncHandler() {

                        final Object asyncLock = new Object();
                        final AtomicBoolean asyncDone = new AtomicBoolean(false);

                        private void check(final JobExecutionResult result) {
                            synchronized ( asyncLock ) {
                                if ( !asyncDone.get() ) {
                                    asyncDone.set(true);
                                    context.asyncProcessingFinished(result);
                                } else {
                                    throw new IllegalStateException("Job is already marked as processed");
                                }
                            }
                        }

                        @Override
                        public void ok() {
                            this.check(context.result().succeeded());
                        }

                        @Override
                        public void failed() {
                            this.check(context.result().failed());
                        }

                        @Override
                        public void cancel() {
                            this.check(context.result().cancelled());
                        }
                    };
            ((JobImpl)job).setProperty(JobConsumer.PROPERTY_JOB_ASYNC_HANDLER, asyncHandler);
            final JobConsumer.JobResult result = this.consumer.process(job);
            if ( result == JobResult.ASYNC ) {
                return null;
            } else if ( result == JobResult.FAILED) {
                return context.result().failed();
            } else if ( result == JobResult.OK) {
                return context.result().succeeded();
            }
            return context.result().cancelled();
        }
    }
}
