/*
 * 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.driver.pipeline;

import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.Pipeliner;
import org.onosproject.net.behaviour.PipelinerContext;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.flow.FlowRuleOperationsContext;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.criteria.PortCriterion;
import org.onosproject.net.flow.criteria.TunnelIdCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.FlowObjectiveStore;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.slf4j.Logger;

import java.util.Optional;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * Driver for OpenstackSwitching.
 */
public class OpenstackPipeline extends DefaultSingleTablePipeline
        implements Pipeliner {

    private final Logger log = getLogger(getClass());
    protected FlowObjectiveStore flowObjectiveStore;
    protected DeviceId deviceId;
    protected ApplicationId appId;
    protected FlowRuleService flowRuleService;

    private static final int SRC_VNI_TABLE = 0;
    private static final int ACL_TABLE = 1;
    private static final int JUMP_TABLE = 2;
    private static final int ROUTING_TABLE = 3;
    private static final int FORWARDING_TABLE = 4;
    private static final int DUMMY_TABLE = 10;
    private static final int LAST_TABLE = FORWARDING_TABLE;

    private static final int DROP_PRIORITY = 0;
    private static final int HIGH_PRIORITY = 30000;
    private static final int TIME_OUT = 0;
    private static final String VIRTUAL_GATEWAY_MAC = "fe:00:00:00:00:02";


    @Override
    public void init(DeviceId deviceId, PipelinerContext context) {
        super.init(deviceId, context);
        ServiceDirectory serviceDirectory = context.directory();
        this.deviceId = deviceId;

        CoreService coreService = serviceDirectory.get(CoreService.class);
        flowRuleService = serviceDirectory.get(FlowRuleService.class);
        flowObjectiveStore = context.store();

        appId = coreService.registerApplication(
                "org.onosproject.driver.OpenstackPipeline");

        initializePipeline();
    }

    @Override
    public void filter(FilteringObjective filteringObjective) {
        super.filter(filteringObjective);
    }

    @Override
    public void next(NextObjective nextObjective) {
        super.next(nextObjective);
    }

    @Override
    public void forward(ForwardingObjective forwardingObjective) {
        FlowRule flowRule;

        switch (forwardingObjective.flag()) {
            case SPECIFIC:
                flowRule = processSpecific(forwardingObjective);
                break;
            case VERSATILE:
                flowRule = processVersatile(forwardingObjective);
                break;
            default:
                fail(forwardingObjective, ObjectiveError.UNKNOWN);
                log.warn("Unknown forwarding flag {}", forwardingObjective.flag());
                return;
        }

        if (forwardingObjective.op().equals(Objective.Operation.ADD)) {
            applyRules(true, flowRule);
        } else {
            applyRules(false, flowRule);
        }

    }

    private void initializePipeline() {
        connectTables(SRC_VNI_TABLE, ACL_TABLE);
        connectTables(ACL_TABLE, JUMP_TABLE);
        setupJumpTable();
    }

    private void connectTables(int fromTable, int toTable) {
        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();

        treatment.transition(toTable);

        FlowRule flowRule = DefaultFlowRule.builder()
                .forDevice(deviceId)
                .withSelector(selector.build())
                .withTreatment(treatment.build())
                .withPriority(DROP_PRIORITY)
                .fromApp(appId)
                .makePermanent()
                .forTable(fromTable)
                .build();

        applyRules(true, flowRule);
    }

    private void setUpTableMissEntry(int table) {
        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();

        treatment.drop();

        FlowRule flowRule = DefaultFlowRule.builder()
                .forDevice(deviceId)
                .withSelector(selector.build())
                .withTreatment(treatment.build())
                .withPriority(DROP_PRIORITY)
                .fromApp(appId)
                .makePermanent()
                .forTable(table)
                .build();

        applyRules(true, flowRule);
    }

    private void setupJumpTable() {
        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();

        selector.matchEthDst(MacAddress.valueOf(VIRTUAL_GATEWAY_MAC));
        treatment.transition(ROUTING_TABLE);

        FlowRule flowRule = DefaultFlowRule.builder()
                .forDevice(deviceId)
                .withSelector(selector.build())
                .withTreatment(treatment.build())
                .withPriority(HIGH_PRIORITY)
                .fromApp(appId)
                .makePermanent()
                .forTable(JUMP_TABLE)
                .build();

        applyRules(true, flowRule);

        selector = DefaultTrafficSelector.builder();
        treatment = DefaultTrafficTreatment.builder();

        treatment.transition(FORWARDING_TABLE);

        flowRule = DefaultFlowRule.builder()
                .forDevice(deviceId)
                .withSelector(selector.build())
                .withTreatment(treatment.build())
                .withPriority(DROP_PRIORITY)
                .fromApp(appId)
                .makePermanent()
                .forTable(JUMP_TABLE)
                .build();

        applyRules(true, flowRule);
    }

    private void applyRules(boolean install, FlowRule flowRule) {
        FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();

        flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);

        flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
            @Override
            public void onSuccess(FlowRuleOperations ops) {
                log.debug("Provisioned vni or forwarding table");
            }

            @Override
            public void onError(FlowRuleOperations ops) {
                log.debug("Failed to privision vni or forwarding table");
            }
        }));
    }

    private FlowRule processVersatile(ForwardingObjective forwardingObjective) {
        log.debug("Processing versatile forwarding objective");

        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
                .forDevice(deviceId)
                .withSelector(forwardingObjective.selector())
                .withTreatment(forwardingObjective.treatment())
                .withPriority(forwardingObjective.priority())
                .fromApp(forwardingObjective.appId())
                .forTable(SRC_VNI_TABLE);

        if (forwardingObjective.permanent()) {
            ruleBuilder.makePermanent();
        } else {
            ruleBuilder.makeTemporary(TIME_OUT);
        }

        return ruleBuilder.build();
    }

    private FlowRule processSpecific(ForwardingObjective forwardingObjective) {
        log.debug("Processing specific forwarding objective");

        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
        Optional<Instruction> group = forwardingObjective.treatment().immediate().stream()
                .filter(i -> i.type() == Instruction.Type.GROUP).findAny();
        int tableType = tableType(forwardingObjective);
        if (tableType != LAST_TABLE && !group.isPresent()) {
            treatment.transition(nextTable(tableType));
        }
        forwardingObjective.treatment().allInstructions().stream()
                .filter(i -> i.type() != Instruction.Type.NOACTION).forEach(treatment::add);

        FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
                .forDevice(deviceId)
                .withSelector(forwardingObjective.selector())
                .withTreatment(treatment.build())
                .withPriority(forwardingObjective.priority())
                .fromApp(forwardingObjective.appId())
                .forTable(tableType);

        if (forwardingObjective.permanent()) {
            ruleBuilder.makePermanent();
        } else {
            ruleBuilder.makeTemporary(TIME_OUT);
        }

        return ruleBuilder.build();
    }

    private int tableType(ForwardingObjective fo) {

        IPCriterion ipSrc = (IPCriterion) fo.selector().getCriterion(Criterion.Type.IPV4_SRC);
        IPCriterion ipDst = (IPCriterion) fo.selector().getCriterion(Criterion.Type.IPV4_DST);
        TunnelIdCriterion tunnelId =
                (TunnelIdCriterion) fo.selector().getCriterion(Criterion.Type.TUNNEL_ID);
        VlanIdCriterion vlanId = (VlanIdCriterion) fo.selector().getCriterion(Criterion.Type.VLAN_VID);
        PortCriterion inPort = (PortCriterion) fo.selector().getCriterion(Criterion.Type.IN_PORT);
        Optional<Instruction> output = fo.treatment().immediate().stream()
                .filter(i -> i.type() == Instruction.Type.OUTPUT).findAny();
        Optional<Instruction> group = fo.treatment().immediate().stream()
                .filter(i -> i.type() == Instruction.Type.GROUP).findAny();

        // TODO: Add the Connection Tracking Table
        if (inPort != null) {
            return SRC_VNI_TABLE;
        } else if ((tunnelId != null && ipSrc != null && ipDst != null) ||
                (vlanId != null && ipSrc != null && ipDst != null) ||
                (ipSrc != null && group.isPresent())) {
            return ROUTING_TABLE;
        } else if (output.isPresent() || (ipDst != null && group.isPresent())) {
            return FORWARDING_TABLE;
        } else if ((ipSrc != null && ipSrc.ip().prefixLength() == 32 &&
                ipDst != null && ipDst.ip().prefixLength() == 32) ||
                (ipSrc != null && ipSrc.ip().prefixLength() == 32 && ipDst == null) ||
                (ipDst != null && ipDst.ip().prefixLength() == 32 && ipSrc == null) ||
                (ipDst != null && ipDst.ip().prefixLength() == 32 && ipSrc != null) ||
                (ipSrc != null && ipSrc.ip().prefixLength() == 32 && ipDst != null)) {
            return ACL_TABLE;
        }

        return DUMMY_TABLE;
    }

    private int nextTable(int baseTable) {
        return baseTable + 1;
    }

    private void fail(Objective obj, ObjectiveError error) {
        obj.context().ifPresent(context -> context.onError(obj, error));
    }
}

