/*
 * Copyright 2016 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.drivers.oplink;

import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.FilteredConnectPoint;
import org.onosproject.net.Link;
import org.onosproject.net.LinkKey;
import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointDescription;
import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState;
import org.onosproject.net.behaviour.protection.ProtectionConfigBehaviour;
import org.onosproject.net.behaviour.protection.TransportEndpointDescription;
import org.onosproject.net.behaviour.protection.TransportEndpointId;
import org.onosproject.net.behaviour.protection.TransportEndpointState;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.net.config.basics.BasicLinkConfig;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.link.LinkService;
import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

import static org.onosproject.drivers.oplink.OplinkNetconfUtility.*;
import static org.onosproject.net.LinkKey.linkKey;
import static org.onosproject.net.optical.OpticalAnnotations.INPUT_PORT_STATUS;
import static org.onosproject.net.optical.OpticalAnnotations.STATUS_IN_SERVICE;
import static org.onosproject.net.optical.OpticalAnnotations.STATUS_OUT_SERVICE;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * Implementations of the protection behaviours for Oplink Optical Protection Switch (OPS).
 *             _____________________
 *            |                     |     4
 *   CLIENT RX|          ---50%-----|----------- PRIMARY TX
 * -----------|----------           |
 *      1     |          ---50%-----|----------- SECONDARY TX
 *            |                     |     6
 *            |    OPLINK OPS BOX   |
 *            |     ___________     |     3
 *   CLIENT TX|    |           |----|----------- PRIMARY RX
 * -----------|----|   SWITCH  |    |
 *      2     |    |___________|----|----------- SECONDARY RX
 *            |_____________________|     5
 *
 *   - Oplink OPS has 6 uni-directional physical ports:
 *      - port 2 is connected to the client side port.
 *      - port 3 is primary port for network side.
 *      - port 5 is secondary port for network side.
 *      - port 1 directly connects to port 4 and 5 with 50/50 split light.
 *   - Traffic protection
 *      - Traffic(Optical light) from client port is broadcasted (50/50 split) to
 *        both primary and secondary ports all the time.
 *      - In fault free condition, traffic from primary port is bridged to client port and
 *        in the case of primary port fails (LOS), traffic is bridged from secondary port to client port.
 *      - User initiated switch (to primary or secondary) is also supported.
 */
public class OplinkOpticalProtectionSwitchConfig extends AbstractHandlerBehaviour
        implements ProtectionConfigBehaviour {

    // key nodes
    private static final String KEY_CONFIG = "config";
    private static final String KEY_OPSCONFIG = "ops-config";
    private static final String KEY_STATE = "state";
    private static final String KEY_OPSSTATE = "ops-state";
    private static final String KEY_NAME_PRIMARY = "primary";
    private static final String KEY_NAME_SECONDARY = "secondary";
    private static final String KEY_OPT_FORCE = "force";
    private static final String KEY_OPT_MANUAL = "manual";
    private static final String KEY_OPT_AUTO = "auto-revertive";

    // operation format: [OPT]-[NAME], eg. force-primary
    private static final String FMT_OPT = "%s-%s";

    // define virtual port number
    private static final PortNumber PORT_VIRTUAL = PortNumber.portNumber(0);
    private static final PortNumber PORT_PRIMARY = PortNumber.portNumber(3, "primary_port");
    private static final PortNumber PORT_SECONDARY = PortNumber.portNumber(5, "secondary_port");
    // log
    private static final Logger log = getLogger(OplinkOpticalProtectionSwitchConfig.class);

    @Override
    public CompletableFuture<ConnectPoint> createProtectionEndpoint(
            ProtectedTransportEndpointDescription configuration) {
        // Add a virtual link between two virtual ports of the device and peer.
        addLink(getPeerId());
        // Only support one group in the device.
        return CompletableFuture.completedFuture(new ConnectPoint(data().deviceId(), PORT_VIRTUAL));
    }

    @Override
    public CompletableFuture<ConnectPoint> updateProtectionEndpoint(ConnectPoint identifier,
            ProtectedTransportEndpointDescription configuration) {
        // The function of updating protection virtual Port is not supported by the device.
        return CompletableFuture.completedFuture(identifier);
    }

    @Override
    public CompletableFuture<Boolean> deleteProtectionEndpoint(ConnectPoint identifier) {
        if (identifier.port().equals(PORT_VIRTUAL)) {
            // Remove the virtual link from peer to the virtual port.
            removeLink(getPeerId());
            return CompletableFuture.completedFuture(true);
        }
        return CompletableFuture.completedFuture(false);
    }

    @Override
    public CompletableFuture<Map<ConnectPoint, ProtectedTransportEndpointDescription>>
        getProtectionEndpointConfigs() {
        // There are two underlying transport entity endpoints in the device.
        Map<ConnectPoint, ProtectedTransportEndpointDescription> map = new HashMap<>();
        map.put(new ConnectPoint(data().deviceId(), PORT_VIRTUAL), buildProtectedTransportEndpointDescription());
        return CompletableFuture.completedFuture(map);
    }

    @Override
    public CompletableFuture<Map<ConnectPoint, ProtectedTransportEndpointState>> getProtectionEndpointStates() {
        Map<ConnectPoint, ProtectedTransportEndpointState> map = new HashMap<>();
        map.put(new ConnectPoint(data().deviceId(), PORT_VIRTUAL), buildProtectedTransportEndpointState());
        return CompletableFuture.completedFuture(map);
    }

    @Override
    public CompletableFuture<Void> switchWorkingPath(ConnectPoint identifier, int index) {
        return switchToManual(identifier, index);
    }

    @Override
    public CompletableFuture<Void> switchToForce(ConnectPoint identifier, int index) {
        return getProtectionEndpointConfig(identifier)
                .thenApply(m -> m.paths().get(index))
                .thenApply(m -> switchDevice(formatOperation(m.output().connectPoint().port(), KEY_OPT_FORCE)))
                .thenApply(m -> null);
    }

    @Override
    public CompletableFuture<Void> switchToManual(ConnectPoint identifier, int index) {
        return getProtectionEndpointConfig(identifier)
                .thenApply(m -> m.paths().get(index))
                .thenApply(m -> switchDevice(formatOperation(m.output().connectPoint().port(), KEY_OPT_MANUAL)))
                .thenApply(m -> null);
    }

    @Override
    public CompletableFuture<Void> switchToAutomatic(ConnectPoint identifier) {
        switchDevice(KEY_OPT_AUTO);
        return CompletableFuture.completedFuture(null);
    }

    private ProtectedTransportEndpointState buildProtectedTransportEndpointState() {
        // First, get active port from device.
        PortNumber activePort = acquireActivePort();
        // Build all endpoint state with port working attribute.
        List<TransportEndpointState> states = new ArrayList<>();
        states.add(buildTransportEndpointState(data().deviceId(), PORT_PRIMARY, activePort));
        states.add(buildTransportEndpointState(data().deviceId(), PORT_SECONDARY, activePort));
        return ProtectedTransportEndpointState.builder()
                .withPathStates(states)
                .withDescription(buildProtectedTransportEndpointDescription())
                .withActivePathIndex(getActiveIndex(states, activePort))
                .build();
    }

    private ProtectedTransportEndpointDescription buildProtectedTransportEndpointDescription() {
        List<TransportEndpointDescription> descs = new ArrayList<>();
        descs.add(buildTransportEndpointDescription(data().deviceId(), PORT_PRIMARY));
        descs.add(buildTransportEndpointDescription(data().deviceId(), PORT_SECONDARY));
        return ProtectedTransportEndpointDescription.of(descs, getPeerId(), FINGERPRINT);
    }

    private TransportEndpointDescription buildTransportEndpointDescription(DeviceId id, PortNumber port) {
        return TransportEndpointDescription.builder()
                .withOutput(new FilteredConnectPoint(new ConnectPoint(id, port)))
                .build();
    }

    private TransportEndpointState buildTransportEndpointState(
            DeviceId id, PortNumber port, PortNumber activePort) {
        String status = port.equals(activePort) ? STATUS_IN_SERVICE : STATUS_OUT_SERVICE;
        Map<String, String> attributes = new HashMap<>();
        attributes.put(INPUT_PORT_STATUS, status);
        return TransportEndpointState.builder()
                .withId(TransportEndpointId.of(port.name()))
                .withDescription(buildTransportEndpointDescription(id, port))
                .addAttributes(attributes)
                .build();
    }

    private int getActiveIndex(List<TransportEndpointState> pathStates, PortNumber activePort) {
        int activeIndex = 0;
        for (TransportEndpointState state : pathStates) {
            if (activePort.equals(state.description().output().connectPoint().port())) {
                return activeIndex;
            }
            ++activeIndex;
        }
        return ProtectedTransportEndpointState.ACTIVE_UNKNOWN;
    }

    private PortNumber acquireActivePort() {
        String filter = new StringBuilder(xmlOpen(KEY_OPENOPTICALDEV_XMLNS))
                .append(xmlOpen(KEY_STATE))
                .append(xmlEmpty(KEY_OPSSTATE))
                .append(xmlClose(KEY_STATE))
                .append(xmlClose(KEY_OPENOPTICALDEV))
                .toString();
        String reply = netconfGet(handler(), filter);
        log.debug("Service state replying, {}", reply);
        return reply.contains(KEY_NAME_PRIMARY) ? PORT_PRIMARY : PORT_SECONDARY;
    }

    private String formatOperation(PortNumber port, String operation) {
        String key = port.name().contains(KEY_NAME_PRIMARY) ? KEY_NAME_PRIMARY : KEY_NAME_SECONDARY;
        return String.format(FMT_OPT, operation, key);
    }

    private boolean switchDevice(String operation) {
        log.debug("Switch to {} for Device {}", operation, data().deviceId());
        String cfg = new StringBuilder(xmlOpen(KEY_OPENOPTICALDEV_XMLNS))
                .append(xmlOpen(KEY_CONFIG))
                .append(xml(KEY_OPSCONFIG, operation))
                .append(xmlClose(KEY_CONFIG))
                .append(xmlClose(KEY_OPENOPTICALDEV))
                .toString();
        return netconfEditConfig(handler(), CFG_MODE_MERGE, cfg);
    }

    private void addLink(DeviceId peerId) {
        if (peerId == null) {
            log.warn("PeerID is null for device {}", data().deviceId());
            return;
        }
        LinkKey link = linkKey(new ConnectPoint(peerId, PORT_VIRTUAL),
                               new ConnectPoint(data().deviceId(), PORT_VIRTUAL));
        handler().get(NetworkConfigService.class).addConfig(link, BasicLinkConfig.class)
                .type(Link.Type.VIRTUAL)
                .apply();
    }

    private void removeLink(DeviceId peerId) {
        if (peerId == null) {
            log.warn("PeerID is null for device {}", data().deviceId());
            return;
        }
        LinkKey link = linkKey(new ConnectPoint(peerId, PORT_VIRTUAL),
                               new ConnectPoint(data().deviceId(), PORT_VIRTUAL));
        handler().get(NetworkConfigService.class).removeConfig(link, BasicLinkConfig.class);
    }

    private DeviceId getPeerId() {
        ConnectPoint dstCp = new ConnectPoint(data().deviceId(), PORT_VIRTUAL);
        Set<Link> links = handler().get(LinkService.class).getIngressLinks(dstCp);
        for (Link l : links) {
            if (l.type() == Link.Type.VIRTUAL) {
                // This device is the destination and peer is the source.
                return l.src().deviceId();
            }
        }
        // None of link found, return itself.
        return data().deviceId();
    }
}
