/*
 * Copyright 2015-present Open Networking Foundation
 *
 * Licensed 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.onosproject.store.intent.impl;

import com.google.common.collect.ImmutableList;
import org.apache.commons.lang.math.RandomUtils;
import org.onlab.util.Backtrace;
import org.onlab.util.KryoNamespace;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.ControllerNode;
import org.onosproject.cluster.NodeId;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentEvent;
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.IntentStore;
import org.onosproject.net.intent.IntentStoreDelegate;
import org.onosproject.net.intent.Key;
import org.onosproject.net.intent.WorkPartitionService;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.Timestamp;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMapBuilder;
import org.onosproject.store.service.EventuallyConsistentMapEvent;
import org.onosproject.store.service.EventuallyConsistentMapListener;
import org.onosproject.store.service.MultiValuedTimestamp;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.WallClockTimestamp;
import org.osgi.service.component.ComponentContext;
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.slf4j.Logger;

import java.util.Collection;
import java.util.Dictionary;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static org.onlab.util.Tools.get;
import static org.onosproject.net.intent.IntentState.PURGE_REQ;
import static org.onosproject.store.OsgiPropertyConstants.GIS_PERSISTENCE_ENABLED;
import static org.onosproject.store.OsgiPropertyConstants.GIS_PERSISTENCE_ENABLED_DEFAULT;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * Manages inventory of Intents in a distributed data store that uses optimistic
 * replication and gossip based techniques.
 */
//FIXME we should listen for leadership changes. if the local instance has just
// ...  become a leader, scan the pending map and process those
@Component(
        immediate = true,
        service = IntentStore.class,
        property = {
                GIS_PERSISTENCE_ENABLED + ":Boolean=" + GIS_PERSISTENCE_ENABLED_DEFAULT
        }
)
public class GossipIntentStore
        extends AbstractStore<IntentEvent, IntentStoreDelegate>
        implements IntentStore {

    private final Logger log = getLogger(getClass());

    private static final boolean PERSIST = false;

    // Map of intent key => current intent state
    private EventuallyConsistentMap<Key, IntentData> currentMap;

    // Map of intent key => pending intent operation
    private EventuallyConsistentMap<Key, IntentData> pendingMap;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected ComponentConfigService configService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected ClusterService clusterService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected StorageService storageService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY)
    protected WorkPartitionService partitionService;

    private final AtomicLong sequenceNumber = new AtomicLong(0);

    private EventuallyConsistentMapListener<Key, IntentData>
            mapCurrentListener = new InternalCurrentListener();

    private EventuallyConsistentMapListener<Key, IntentData>
            mapPendingListener = new InternalPendingListener();

    //Denotes the initial persistence value for this structure
    private boolean initiallyPersistent = false;

    //TODO this is currently an experimental feature used for performance
    // evaluation, enabling persistence with persist the intents but they will
    // not be reinstalled and network state will not be consistent with the
    // intents on cluster restart

    /** EXPERIMENTAL: Enable intent persistence. */
    private boolean persistenceEnabled = GIS_PERSISTENCE_ENABLED_DEFAULT;


    /**
     * TimestampProvieder for currentMap.
     *
     * @param key Intent key
     * @param data Intent data
     * @return generated time stamp
     */
    private Timestamp currentTimestampProvider(Key key, IntentData data) {
        // vector timestamp consisting from 3 components
        //  (request timestamp, internal state, sequence #)

        // 2nd component required to avoid compilation result overwriting installation state
        //    note: above is likely to be a sign of design issue in transition to installation phase
        // 3rd component required for generating new timestamp for removal..
        return  new MultiValuedTimestamp<>(
                Optional.ofNullable(data.version()).orElseGet(WallClockTimestamp::new),
                    new MultiValuedTimestamp<>(data.internalStateVersion(),
                            sequenceNumber.incrementAndGet()));
    }

    @Activate
    public void activate(ComponentContext context) {
        configService.registerProperties(getClass());
        modified(context);
        //TODO persistent intents must be reevaluated and the appropriate
        //processing done here, current implementation is not functional
        //and is for performance evaluation only
        initiallyPersistent = persistenceEnabled;
        KryoNamespace.Builder intentSerializer = KryoNamespace.newBuilder()
                .register(KryoNamespaces.API)
                .register(IntentData.class)
                .register(MultiValuedTimestamp.class);

        EventuallyConsistentMapBuilder currentECMapBuilder =
                storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
                .withName("intent-current")
                .withSerializer(intentSerializer)
                .withTimestampProvider(this::currentTimestampProvider)
                .withPeerUpdateFunction((key, intentData) -> getPeerNodes(key, intentData));

        EventuallyConsistentMapBuilder pendingECMapBuilder =
                storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
                .withName("intent-pending")
                .withSerializer(intentSerializer)
                .withTimestampProvider((key, intentData) ->
                        /*
                            We always want to accept new values in the pending map,
                            so we should use a high performance logical clock.
                        */
                        /*
                            TODO We use the wall clock for the time being, but
                            this could result in issues if there is clock skew
                            across instances.
                         */
                        new MultiValuedTimestamp<>(new WallClockTimestamp(), System.nanoTime()))
                .withPeerUpdateFunction((key, intentData) -> getPeerNodes(key, intentData));
        if (initiallyPersistent) {
            currentECMapBuilder = currentECMapBuilder.withPersistence();
            pendingECMapBuilder = pendingECMapBuilder.withPersistence();
        }
        currentMap = currentECMapBuilder.build();
        pendingMap = pendingECMapBuilder.build();

        currentMap.addListener(mapCurrentListener);
        pendingMap.addListener(mapPendingListener);

        log.info("Started");
    }

    @Deactivate
    public void deactivate() {
        if (initiallyPersistent && !persistenceEnabled) {
            pendingMap.clear();
            currentMap.clear();
            log.debug("Persistent state has been purged");
        }
        currentMap.removeListener(mapCurrentListener);
        pendingMap.removeListener(mapPendingListener);
        currentMap.destroy();
        pendingMap.destroy();

        log.info("Stopped");
    }

    @Modified
    public void modified(ComponentContext context) {
        Dictionary<?, ?> properties = context != null ? context.getProperties()
                : new Properties();
        try {
            String s = get(properties, GIS_PERSISTENCE_ENABLED);
            persistenceEnabled =  isNullOrEmpty(s) ? PERSIST :
                    Boolean.parseBoolean(s.trim());
        } catch (Exception e) {
            persistenceEnabled = initiallyPersistent;
            log.error("Failed to retrieve the property value for persist," +
                              "defaulting to the initial setting of \"{}\"" +
                              "any persistent state will not be purged, if " +
                              "this occurred at startup changes made in this" +
                              "session will not be persisted to disk",
                      initiallyPersistent);
        }
        if (persistenceEnabled) {
            //FIXME persistence is an experimental feature, warnings can be removed
            //when the feature is completed
            log.warn("Persistence is an experimental feature, it is not fully " +
                             "functional and is intended only for " +
                             "performance evaluation");
        }
        if (!initiallyPersistent && !persistenceEnabled) {
            log.info("Persistence is set to \"false\", this was the initial" +
                             " setting so no state will be purged or " +
                             "persisted");
        } else if (!initiallyPersistent && persistenceEnabled) {
            log.info("Persistence is set to \"true\", entries will be begin " +
                             "to be persisted after restart");
        } else if (initiallyPersistent && !persistenceEnabled) {
            log.info("Persistence is set to \"false\", all persistent state " +
                             "will be purged on next shutdown");
        } else {
            log.info("Persistence is set to \"true\", entries from this and" +
                             " subsequent sessions will be persisted");
        }


    }

    @Override
    public long getIntentCount() {
        return currentMap.size();
    }

    @Override
    public Iterable<Intent> getIntents() {
        return currentMap.values().stream()
                .map(IntentData::intent)
                .collect(Collectors.toList());
    }

    @Override
    public Iterable<IntentData> getIntentData(boolean localOnly, long olderThan) {
        if (localOnly || olderThan > 0) {
            long now = System.currentTimeMillis();
            final WallClockTimestamp time = new WallClockTimestamp(now - olderThan);
            return currentMap.values().stream()
                    .filter(data -> data.version().isOlderThan(time) &&
                            (!localOnly || isMaster(data.key())))
                    .collect(Collectors.toList());
        }
        return currentMap.values();
    }

    @Override
    public IntentState getIntentState(Key intentKey) {
        IntentData data = currentMap.get(intentKey);
        if (data != null) {
            return data.state();
        }
        return null;
    }

    @Override
    public List<Intent> getInstallableIntents(Key intentKey) {
        IntentData data = currentMap.get(intentKey);
        if (data != null) {
            return data.installables();
        }
        return ImmutableList.of();
    }

    @Override
    public void write(IntentData newData) {
        checkNotNull(newData);

        IntentData currentData = currentMap.get(newData.key());
        if (IntentData.isUpdateAcceptable(currentData, newData)) {
            // Only the master is modifying the current state. Therefore assume
            // this always succeeds
            if (newData.state() == PURGE_REQ) {
                if (currentData != null) {
                    if (log.isTraceEnabled()) {
                        log.trace("Purging {} in currentMap. {}@{}",
                                  newData.key(), newData.state(), newData.version(),
                                  new Backtrace());
                    }
                    currentMap.remove(newData.key(), currentData);
                } else {
                    log.info("Gratuitous purge request for intent: {}", newData.key());
                }
            } else {
                if (log.isTraceEnabled()) {
                    log.trace("Putting {} in currentMap. {}@{}",
                              newData.key(), newData.state(), newData.version(),
                              new Backtrace());
                }
                currentMap.put(newData.key(), IntentData.copy(newData));
            }
        } else {
            log.debug("Update for {} not acceptable from:\n{}\nto:\n{}",
                      newData.key(), currentData, newData);
        }
        // Remove the intent data from the pending map if the newData is more
        // recent or equal to the existing entry. No matter if it is an acceptable
        // update or not
        Key key = newData.key();
        IntentData existingValue = pendingMap.get(key);

        if (existingValue == null) {
            return;
        }

        if (!existingValue.version().isNewerThan(newData.version())) {
            pendingMap.remove(key, existingValue);
        } else {
            log.debug("{} in pending map was newer, leaving it there", key);
        }
    }

    private Collection<NodeId> getPeerNodes(Key key, IntentData data) {
        NodeId master = partitionService.getLeader(key, Key::hash);
        NodeId origin = (data != null) ? data.origin() : null;
        if (data != null && (master == null || origin == null)) {
            log.debug("Intent {} missing master and/or origin; master = {}, origin = {}",
                      key, master, origin);
        }

        NodeId me = clusterService.getLocalNode().id();
        boolean isMaster = Objects.equals(master, me);
        boolean isOrigin = Objects.equals(origin, me);
        if (isMaster && isOrigin) {
            return getRandomNode();
        } else if (isMaster) {
            return origin != null ? ImmutableList.of(origin) : getRandomNode();
        } else if (isOrigin) {
            return master != null ? ImmutableList.of(master) : getRandomNode();
        } else {
            log.warn("No master or origin for intent {}", key);
            return master != null ? ImmutableList.of(master) : getRandomNode();
        }
    }

    private List<NodeId> getRandomNode() {
        NodeId me = clusterService.getLocalNode().id();
        List<NodeId> nodes = clusterService.getNodes().stream()
                .map(ControllerNode::id)
                .filter(node -> !Objects.equals(node, me))
                .collect(Collectors.toList());
        if (nodes.isEmpty()) {
            return ImmutableList.of();
        }
        return ImmutableList.of(nodes.get(RandomUtils.nextInt(nodes.size())));
    }

    @Override
    public void batchWrite(Iterable<IntentData> updates) {
        updates.forEach(this::write);
    }

    @Override
    public Intent getIntent(Key key) {
        IntentData data = currentMap.get(key);
        if (data != null) {
            return data.intent();
        }
        return null;
    }

    @Override
    public IntentData getIntentData(Key key) {
        IntentData current = currentMap.get(key);
        if (current == null) {
            return null;
        }
        return IntentData.copy(current);
    }

    @Override
    public void addPending(IntentData data) {
        checkNotNull(data);
        if (data.version() == null) {
            // Copy IntentData including request state in this way we can
            // avoid the creation of Intents with state == request, which can
            // be problematic if the Intent state is different from *REQ
            // {INSTALL_, WITHDRAW_ and PURGE_}.
            pendingMap.put(data.key(), IntentData.assign(data,
                                                         new WallClockTimestamp(),
                                                         clusterService.getLocalNode().id()));
        } else {
            pendingMap.compute(data.key(), (key, existingValue) -> {
                if (existingValue == null || existingValue.version().isOlderThan(data.version())) {
                    return IntentData.assign(data, data.version(), clusterService.getLocalNode().id());
                } else {
                    return existingValue;
                }
            });
        }

    }

    @Override
    public boolean isMaster(Key intentKey) {
        return partitionService.isMine(intentKey, Key::hash);
    }

    @Override
    public Iterable<Intent> getPending() {
        return pendingMap.values().stream()
                .map(IntentData::intent)
                .collect(Collectors.toList());
    }

    @Override
    public Iterable<IntentData> getPendingData() {
        return pendingMap.values();
    }

    @Override
    public IntentData getPendingData(Key intentKey) {
        return pendingMap.get(intentKey);
    }

    @Override
    public Iterable<IntentData> getPendingData(boolean localOnly, long olderThan) {
        long now = System.currentTimeMillis();
        final WallClockTimestamp time = new WallClockTimestamp(now - olderThan);
        return pendingMap.values().stream()
                .filter(data -> data.version().isOlderThan(time) &&
                        (!localOnly || isMaster(data.key())))
                .collect(Collectors.toList());
    }

    private final class InternalCurrentListener implements
            EventuallyConsistentMapListener<Key, IntentData> {
        @Override
        public void event(EventuallyConsistentMapEvent<Key, IntentData> event) {
            IntentData intentData = event.value();
            if (event.type() == EventuallyConsistentMapEvent.Type.PUT) {
                // The current intents map has been updated. If we are master for
                // this intent's partition, notify the Manager that it should
                // emit notifications about updated tracked resources.
                if (delegate != null && isMaster(event.value().intent().key())) {
                    delegate.onUpdate(IntentData.copy(intentData)); // copy for safety, likely unnecessary
                }
                IntentEvent.getEvent(intentData).ifPresent(e -> notifyDelegate(e));
            }
        }
    }

    private final class InternalPendingListener implements
            EventuallyConsistentMapListener<Key, IntentData> {
        @Override
        public void event(
                EventuallyConsistentMapEvent<Key, IntentData> event) {
            if (event.type() == EventuallyConsistentMapEvent.Type.PUT) {
                // The pending intents map has been updated. If we are master for
                // this intent's partition, notify the Manager that it should do
                // some work.
                if (isMaster(event.value().intent().key())) {
                    if (delegate != null) {
                        delegate.process(IntentData.copy(event.value()));
                    }
                }

                IntentEvent.getEvent(event.value()).ifPresent(e -> notifyDelegate(e));
            }
        }
    }

}

