/*
 * Copyright 2016-present Open Networking Laboratory
 *
 * 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.drivers.bmv2;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.tuple.Pair;
import org.onlab.osgi.ServiceNotFoundException;
import org.onosproject.bmv2.api.context.Bmv2Configuration;
import org.onosproject.bmv2.api.context.Bmv2DeviceContext;
import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator;
import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslatorException;
import org.onosproject.bmv2.api.context.Bmv2Interpreter;
import org.onosproject.bmv2.api.context.Bmv2TableModel;
import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
import org.onosproject.bmv2.api.runtime.Bmv2FlowRuleWrapper;
import org.onosproject.bmv2.api.runtime.Bmv2MatchKey;
import org.onosproject.bmv2.api.runtime.Bmv2ParsedTableEntry;
import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
import org.onosproject.bmv2.api.runtime.Bmv2TableEntry;
import org.onosproject.bmv2.api.runtime.Bmv2TableEntryReference;
import org.onosproject.bmv2.api.service.Bmv2Controller;
import org.onosproject.bmv2.api.service.Bmv2DeviceContextService;
import org.onosproject.bmv2.api.service.Bmv2TableEntryService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.flow.DefaultFlowEntry;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleProgrammable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static org.onosproject.bmv2.api.runtime.Bmv2RuntimeException.Code.*;
import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED;

/**
 * Implementation of the flow rule programmable behaviour for BMv2.
 */
public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implements FlowRuleProgrammable {

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

    // Needed to synchronize operations over the same table entry.
    private static final ConcurrentMap<Bmv2TableEntryReference, Lock> ENTRY_LOCKS = Maps.newConcurrentMap();

    private Bmv2Controller controller;
    private Bmv2TableEntryService tableEntryService;
    private Bmv2DeviceContextService contextService;

    private boolean init() {
        try {
            controller = handler().get(Bmv2Controller.class);
            tableEntryService = handler().get(Bmv2TableEntryService.class);
            contextService = handler().get(Bmv2DeviceContextService.class);
            return true;
        } catch (ServiceNotFoundException e) {
            log.warn(e.getMessage());
            return false;
        }
    }

    @Override
    public Collection<FlowEntry> getFlowEntries() {

        if (!init()) {
            return Collections.emptyList();
        }

        DeviceId deviceId = handler().data().deviceId();

        Bmv2DeviceAgent deviceAgent;
        try {
            deviceAgent = controller.getAgent(deviceId);
        } catch (Bmv2RuntimeException e) {
            log.error("Failed to get BMv2 device agent: {}", e.explain());
            return Collections.emptyList();
        }

        Bmv2DeviceContext context = contextService.getContext(deviceId);
        if (context == null) {
            log.warn("Unable to get device context for {}", deviceId);
            return Collections.emptyList();
        }

        Bmv2Interpreter interpreter = context.interpreter();
        Bmv2Configuration configuration = context.configuration();

        List<FlowEntry> entryList = Lists.newArrayList();

        for (Bmv2TableModel table : configuration.tables()) {
            // For each table in the configuration AND exposed by the interpreter.
            if (!interpreter.tableIdMap().inverse().containsKey(table.name())) {
                continue; // next table
            }

            List<Bmv2ParsedTableEntry> installedEntries;
            try {
                installedEntries = deviceAgent.getTableEntries(table.name());
            } catch (Bmv2RuntimeException e) {
                log.warn("Failed to get table entries of table {} of {}: {}", table.name(), deviceId, e.explain());
                continue; // next table
            }

            for (Bmv2ParsedTableEntry parsedEntry : installedEntries) {
                Bmv2TableEntryReference entryRef = new Bmv2TableEntryReference(deviceId, table.name(),
                                                                               parsedEntry.matchKey());

                Lock lock = ENTRY_LOCKS.computeIfAbsent(entryRef, key -> new ReentrantLock());
                lock.lock();

                try {
                    Bmv2FlowRuleWrapper frWrapper = tableEntryService.lookup(entryRef);

                    if (frWrapper == null) {
                        log.debug("Missing reference from table entry service. Deleting it. BUG? " +
                                         "deviceId={}, tableName={}, matchKey={}",
                                 deviceId, table.name(), entryRef.matchKey());
                        try {
                            doRemove(deviceAgent, table.name(), parsedEntry.entryId(), parsedEntry.matchKey());
                        } catch (Bmv2RuntimeException e) {
                            log.warn("Unable to remove inconsistent flow rule: {}", e.explain());
                        }
                        continue; // next entry
                    }

                    long remoteEntryId = parsedEntry.entryId();
                    long localEntryId = frWrapper.entryId();

                    if (remoteEntryId != localEntryId) {
                        log.debug("getFlowEntries(): inconsistent entry id! BUG? Updating it... remote={}, local={}",
                                 remoteEntryId, localEntryId);
                        frWrapper = new Bmv2FlowRuleWrapper(frWrapper.rule(), remoteEntryId,
                                                            frWrapper.installedOnMillis());
                        tableEntryService.bind(entryRef, frWrapper);
                    }

                    long bytes = 0L;
                    long packets = 0L;

                    if (table.hasCounters()) {
                        // Read counter values from device.
                        try {
                            Pair<Long, Long> counterValue = deviceAgent.readTableEntryCounter(table.name(),
                                                                                              remoteEntryId);
                            bytes = counterValue.getLeft();
                            packets = counterValue.getRight();
                        } catch (Bmv2RuntimeException e) {
                            log.warn("Unable to get counters for entry {}/{} of device {}: {}",
                                     table.name(), remoteEntryId, deviceId, e.explain());
                        }
                    }

                    FlowEntry entry = new DefaultFlowEntry(frWrapper.rule(), ADDED, frWrapper.lifeInSeconds(),
                                                           packets, bytes);
                    entryList.add(entry);

                } finally {
                    lock.unlock();
                }
            }
        }

        return Collections.unmodifiableCollection(entryList);
    }

    @Override
    public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {

        return processFlowRules(rules, Operation.APPLY);
    }

    @Override
    public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {

        return processFlowRules(rules, Operation.REMOVE);
    }

    private Collection<FlowRule> processFlowRules(Collection<FlowRule> rules, Operation operation) {

        if (!init()) {
            return Collections.emptyList();
        }

        DeviceId deviceId = handler().data().deviceId();

        Bmv2DeviceAgent deviceAgent;
        try {
            deviceAgent = controller.getAgent(deviceId);
        } catch (Bmv2RuntimeException e) {
            log.error("Failed to get BMv2 device agent: {}", e.explain());
            return Collections.emptyList();
        }

        Bmv2DeviceContext context = contextService.getContext(deviceId);
        if (context == null) {
            log.error("Unable to get device context for {}", deviceId);
            return Collections.emptyList();
        }

        Bmv2FlowRuleTranslator translator = tableEntryService.getFlowRuleTranslator();

        List<FlowRule> processedFlowRules = Lists.newArrayList();

        for (FlowRule rule : rules) {

            Bmv2TableEntry bmv2Entry;

            try {
                bmv2Entry = translator.translate(rule, context);
            } catch (Bmv2FlowRuleTranslatorException e) {
                log.warn("Unable to translate flow rule: {} - {}", e.getMessage(), rule);
                continue; // next rule
            }

            String tableName = bmv2Entry.tableName();
            Bmv2TableEntryReference entryRef = new Bmv2TableEntryReference(deviceId, tableName, bmv2Entry.matchKey());

            Lock lock = ENTRY_LOCKS.computeIfAbsent(entryRef, k -> new ReentrantLock());
            lock.lock();
            try {
                // Get from store
                Bmv2FlowRuleWrapper frWrapper = tableEntryService.lookup(entryRef);
                try {
                    if (operation == Operation.APPLY) {
                        // Apply entry
                        long entryId;
                        if (frWrapper != null) {
                            // Existing entry.
                            entryId = frWrapper.entryId();
                            // Tentatively delete entry before re-adding.
                            // It might not exist on device due to inconsistencies.
                            silentlyRemove(deviceAgent, entryRef.tableName(), entryId);
                        }
                        // Add entry.
                        entryId = doAddEntry(deviceAgent, bmv2Entry);
                        frWrapper = new Bmv2FlowRuleWrapper(rule, entryId, System.currentTimeMillis());
                    } else {
                        // Remove entry
                        if (frWrapper == null) {
                            // Entry not found in map, how come?
                            forceRemove(deviceAgent, entryRef.tableName(), entryRef.matchKey());
                        } else {
                            long entryId = frWrapper.entryId();
                            doRemove(deviceAgent, entryRef.tableName(), entryId, entryRef.matchKey());
                        }
                        frWrapper = null;
                    }
                    // If here, no exceptions... things went well :)
                    processedFlowRules.add(rule);
                } catch (Bmv2RuntimeException e) {
                    log.warn("Unable to {} flow rule: {}", operation.name(), e.explain());
                }

                // Update entryRef binding in table entry service.
                if (frWrapper != null) {
                    tableEntryService.bind(entryRef, frWrapper);
                } else {
                    tableEntryService.unbind(entryRef);
                }
            } finally {
                lock.unlock();
            }
        }

        return processedFlowRules;
    }

    private long doAddEntry(Bmv2DeviceAgent agent, Bmv2TableEntry entry) throws Bmv2RuntimeException {
        try {
            return agent.addTableEntry(entry);
        } catch (Bmv2RuntimeException e) {
            if (e.getCode().equals(TABLE_DUPLICATE_ENTRY)) {
                forceRemove(agent, entry.tableName(), entry.matchKey());
                return agent.addTableEntry(entry);
            } else {
                throw e;
            }
        }
    }

    private void doRemove(Bmv2DeviceAgent agent, String tableName, long entryId, Bmv2MatchKey matchKey)
            throws Bmv2RuntimeException {
        try {
            agent.deleteTableEntry(tableName, entryId);
        } catch (Bmv2RuntimeException e) {
            if (e.getCode().equals(TABLE_INVALID_HANDLE) || e.getCode().equals(TABLE_EXPIRED_HANDLE)) {
                // entry is not there with the declared ID, try with a forced remove.
                forceRemove(agent, tableName, matchKey);
            } else {
                throw e;
            }
        }
    }

    private void forceRemove(Bmv2DeviceAgent agent, String tableName, Bmv2MatchKey matchKey)
            throws Bmv2RuntimeException {
        // Find the entryID (expensive call!)
        for (Bmv2ParsedTableEntry pEntry : agent.getTableEntries(tableName)) {
            if (pEntry.matchKey().equals(matchKey)) {
                // Remove entry and drop exceptions.
                silentlyRemove(agent, tableName, pEntry.entryId());
                break;
            }
        }
    }

    private void silentlyRemove(Bmv2DeviceAgent agent, String tableName, long entryId) {
        try {
            agent.deleteTableEntry(tableName, entryId);
        } catch (Bmv2RuntimeException e) {
            // do nothing
        }
    }

    private enum Operation {
        APPLY, REMOVE
    }
}
