/*
 * 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.incubator.net.config.basics;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.config.Config;
import org.onosproject.net.host.InterfaceIpAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Configuration for interfaces.
 */
@Beta
public class InterfaceConfig extends Config<ConnectPoint> {
    private static Logger log = LoggerFactory.getLogger(InterfaceConfig.class);

    public static final String NAME = "name";
    public static final String IPS = "ips";
    public static final String MAC = "mac";
    public static final String VLAN = "vlan";
    public static final String VLAN_UNTAGGED = "vlan-untagged";
    public static final String VLAN_TAGGED = "vlan-tagged";
    public static final String VLAN_NATIVE = "vlan-native";

    private static final String CONFIG_VALUE_ERROR = "Error parsing config value";
    private static final String INTF_NULL_ERROR = "Interface cannot be null";
    private static final String INTF_NAME_ERROR = "Interface must have a valid name";

    @Override
    public boolean isValid() {
        for (JsonNode node : array) {
            if (!hasOnlyFields((ObjectNode) node, NAME, IPS, MAC, VLAN,
                    VLAN_UNTAGGED, VLAN_TAGGED, VLAN_NATIVE)) {
                return false;
            }

            ObjectNode obj = (ObjectNode) node;

            if (!(isString(obj, NAME, FieldPresence.OPTIONAL) &&
                    isMacAddress(obj, MAC, FieldPresence.OPTIONAL) &&
                    isIntegralNumber(obj, VLAN, FieldPresence.OPTIONAL, 0, VlanId.MAX_VLAN) &&
                    isIntegralNumber(obj, VLAN_UNTAGGED, FieldPresence.OPTIONAL, 0, VlanId.MAX_VLAN) &&
                    isIntegralNumber(obj, VLAN_NATIVE, FieldPresence.OPTIONAL, 0, VlanId.MAX_VLAN))) {
                return false;
            }

            for (JsonNode ipNode : node.path(IPS)) {
                if (!ipNode.isTextual() || IpPrefix.valueOf(ipNode.asText()) == null) {
                    return false;
                }
            }

            checkArgument(!hasField(obj, VLAN_TAGGED) ||
                            (node.path(VLAN_TAGGED).isArray() && node.path(VLAN_TAGGED).size() >= 1),
                    "%s must be an array with at least one element", VLAN_TAGGED);

            for (JsonNode vlanNode : node.path(VLAN_TAGGED)) {
                checkArgument(vlanNode.isInt() &&
                        vlanNode.intValue() >= 0 &&  vlanNode.intValue() <= VlanId.MAX_VLAN,
                        "Invalid VLAN ID %s in %s", vlanNode.intValue(), VLAN_TAGGED);
            }

            checkArgument(!hasField(obj, VLAN_UNTAGGED) ||
                    !(hasField(obj, VLAN_TAGGED) || hasField(obj, VLAN_NATIVE)),
                    "%s and %s should not be used when %s is set", VLAN_TAGGED, VLAN_NATIVE, VLAN_UNTAGGED);

            checkArgument(!hasField(obj, VLAN_TAGGED) || !hasField(obj, VLAN_UNTAGGED),
                    "%s should not be used when %s is set", VLAN_UNTAGGED, VLAN_TAGGED);

            checkArgument(!hasField(obj, VLAN_NATIVE) || hasField(obj, VLAN_TAGGED),
                    "%s should not be used alone without %s", VLAN_NATIVE, VLAN_TAGGED);

            checkArgument(!hasField(obj, VLAN_NATIVE) || !hasField(obj, VLAN_TAGGED) ||
                    !getVlans(obj, VLAN_TAGGED).contains(getVlan(obj, VLAN_NATIVE)),
                    "%s cannot be one of the VLANs configured in %s", VLAN_NATIVE, VLAN_TAGGED);
        }
        return true;
    }

    /**
     * Retrieves all interfaces configured on this port.
     *
     * @return set of interfaces
     * @throws ConfigException if there is any error in the JSON config
     */
    public Set<Interface> getInterfaces() throws ConfigException {
        Set<Interface> interfaces = Sets.newHashSet();

        try {
            for (JsonNode intfNode : array) {
                String name = intfNode.path(NAME).asText(null);

                List<InterfaceIpAddress> ips = getIps(intfNode);

                String mac = intfNode.path(MAC).asText();
                MacAddress macAddr = mac.isEmpty() ? null : MacAddress.valueOf(mac);

                VlanId vlan = getVlan(intfNode, VLAN);
                VlanId vlanUntagged = getVlan(intfNode, VLAN_UNTAGGED);
                Set<VlanId> vlanTagged = getVlans(intfNode, VLAN_TAGGED);
                VlanId vlanNative = getVlan(intfNode, VLAN_NATIVE);

                interfaces.add(new Interface(name, subject, ips, macAddr, vlan,
                        vlanUntagged, vlanTagged, vlanNative));
            }
        } catch (IllegalArgumentException e) {
            throw new ConfigException(CONFIG_VALUE_ERROR, e);
        }

        return interfaces;
    }

    /**
     * Adds an interface to the config.
     *
     * @param intf interface to add
     */
    public void addInterface(Interface intf) {
        checkNotNull(intf, INTF_NULL_ERROR);
        checkArgument(!intf.name().equals(Interface.NO_INTERFACE_NAME), INTF_NAME_ERROR);

        // Remove old interface with this name if it exists
        removeInterface(intf.name());

        ObjectNode intfNode = array.addObject();

        intfNode.put(NAME, intf.name());

        if (intf.mac() != null) {
            intfNode.put(MAC, intf.mac().toString());
        }

        if (!intf.ipAddressesList().isEmpty()) {
            intfNode.set(IPS, putIps(intf.ipAddressesList()));
        }

        if (!intf.vlan().equals(VlanId.NONE)) {
            intfNode.put(VLAN, intf.vlan().toString());
        }

        if (!intf.vlanUntagged().equals(VlanId.NONE)) {
            intfNode.put(VLAN_UNTAGGED, intf.vlanUntagged().toString());
        }

        if (!intf.vlanTagged().isEmpty()) {
            intfNode.set(VLAN_UNTAGGED, putVlans(intf.vlanTagged()));
        }

        if (!intf.vlanNative().equals(VlanId.NONE)) {
            intfNode.put(VLAN_NATIVE, intf.vlanNative().toString());
        }
    }

    /**
     * Removes an interface from the config.
     *
     * @param name name of the interface to remove
     */
    public void removeInterface(String name) {
        checkNotNull(name, INTF_NULL_ERROR);
        checkArgument(!name.equals(Interface.NO_INTERFACE_NAME), INTF_NAME_ERROR);

        Iterator<JsonNode> it = array.iterator();
        while (it.hasNext()) {
            JsonNode node = it.next();
            if (node.path(NAME).asText().equals(name)) {
                it.remove();
                break;
            }
        }
    }

    /**
     * Extracts VLAN ID from given path of given json node.
     *
     * @param node JSON node
     * @param path path
     * @return VLAN ID
     */
    private VlanId getVlan(JsonNode node, String path) {
        VlanId vlan = VlanId.NONE;
        if (!node.path(path).isMissingNode()) {
            vlan = VlanId.vlanId(Short.valueOf(node.path(path).asText()));
        }
        return vlan;
    }

    /**
     * Extracts a set of VLAN ID from given path of given json node.
     *
     * @param node JSON node
     * @param path path
     * @return a set of VLAN ID
     */
    private Set<VlanId> getVlans(JsonNode node, String path) {
        ImmutableSet.Builder<VlanId> vlanIdBuilder = ImmutableSet.builder();

        JsonNode vlansNode = node.get(path);
        if (vlansNode != null) {
            vlansNode.forEach(vlanNode ->
                    vlanIdBuilder.add(VlanId.vlanId(vlanNode.shortValue())));
        }

        return vlanIdBuilder.build();
    }

    private ArrayNode putVlans(Set<VlanId> vlans) {
        ArrayNode vlanArray = mapper.createArrayNode();

        vlans.forEach(vlan -> vlanArray.add(vlan.toShort()));

        return vlanArray;
    }

    private List<InterfaceIpAddress> getIps(JsonNode node) {
        List<InterfaceIpAddress> ips = Lists.newArrayList();

        JsonNode ipsNode = node.get(IPS);
        if (ipsNode != null) {
            ipsNode.forEach(jsonNode ->
                    ips.add(InterfaceIpAddress.valueOf(jsonNode.asText())));
        }

        return ips;
    }

    private ArrayNode putIps(List<InterfaceIpAddress> intfIpAddresses) {
        ArrayNode ipArray = mapper.createArrayNode();

        intfIpAddresses.forEach(i -> ipArray.add(i.toString()));

        return ipArray;
    }

}
