package org.ovirt.engine.core.vdsbroker.vdsbroker;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.common.businessentities.VdsNetworkInterface;
import org.ovirt.engine.core.common.businessentities.network;
import org.ovirt.engine.core.common.vdscommands.SetupNetworksVdsCommandParameters;
import org.ovirt.engine.core.compat.StringHelper;
import org.ovirt.engine.core.utils.NetworkUtils;
import org.ovirt.engine.core.vdsbroker.xmlrpc.XmlRpcStruct;

public class SetupNetworksVDSCommand<T extends SetupNetworksVdsCommandParameters> extends FutureVDSCommand<T> {

    protected static final String DHCP_BOOT_PROTOCOL = "dhcp";
    protected static final String BOOT_PROTOCOL = "bootproto";
    protected static final String BONDING_OPTIONS = "options";
    protected static final String SLAVES = "nics";
    private static final Map<String, String> REMOVE_OBJ = Collections.singletonMap("remove", Boolean.TRUE.toString());

    public SetupNetworksVDSCommand(T parameters) {
        super(parameters);
    }

    @Override
    protected void ExecuteVdsBrokerCommand() {
        httpTask = getBroker().setupNetworks(generateNetworks(), generateBonds(), generateOptions());
    }

    private XmlRpcStruct generateNetworks() {
        XmlRpcStruct networks = new XmlRpcStruct();

        for (network net : getParameters().getNetworks()) {
            Map<String, String> opts = new HashMap<String, String>();
            VdsNetworkInterface i = findNetworkInterface(net.getname(), getParameters().getInterfaces(),
                    getParameters().getBonds());
            String type = (i.getBonded() != null && i.getBonded()) ? "bonding" : "nic";

            opts.put(type, NetworkUtils.StripVlan(i.getName()));
            if (net.getvlan_id() != null) {
                opts.put("vlan", net.getvlan_id().toString());
            }
            // TODO: add bootproto to network object
            switch (i.getBootProtocol()) {
            case Dhcp:
                opts.put(BOOT_PROTOCOL, DHCP_BOOT_PROTOCOL);
                break;
            case StaticIp:
                putIfNotEmpty(opts, "ipaddr", i.getAddress());
                putIfNotEmpty(opts, "netmask", i.getSubnet());
                putIfNotEmpty(opts, "gateway", i.getGateway());
                break;
            }

            if (net.getMtu() != 0) {
                opts.put("mtu", String.valueOf(net.getMtu()));
            }

            opts.put("bridged", Boolean.toString(net.isVmNetwork()));
            networks.add(net.getname(), opts);
        }

        for (String net : getParameters().getRemovedNetworks()) {
            networks.add(net, REMOVE_OBJ);
        }

        return networks;
    }

    private XmlRpcStruct generateBonds() {
        XmlRpcStruct bonds = new XmlRpcStruct();

        for (VdsNetworkInterface bond : getParameters().getBonds()) {
            XmlRpcStruct opts = new XmlRpcStruct();
            opts.add(SLAVES, getBondNics(bond, getParameters().getInterfaces()));

            if (!StringHelper.isNullOrEmpty(bond.getBondOptions())) {
                opts.add(BONDING_OPTIONS, bond.getBondOptions());
            }
            bonds.add(bond.getName(), opts);
        }

        for (VdsNetworkInterface bond : getParameters().getRemovedBonds()) {
            bonds.add(bond.getName(), REMOVE_OBJ);
        }

        return bonds;
    }

    private XmlRpcStruct generateOptions() {
        XmlRpcStruct options = new XmlRpcStruct();

        options.add(VdsProperties.connectivityCheck, Boolean.toString(getParameters().isCheckConnectivity()));

        if (getParameters().getConectivityTimeout() >= 0) {
            options.add(VdsProperties.connectivityTimeout, getParameters().getConectivityTimeout());
        }
        return options;
    }

    private static void putIfNotEmpty(Map<String, String> map, String key, String value) {
        if (!StringUtils.isEmpty(value)) {
            map.put(key, value);
        }
    }

    private List<String> getBondNics(VdsNetworkInterface bond, List<VdsNetworkInterface> interfaces) {
        List<String> nics = new ArrayList<String>();

        for (VdsNetworkInterface i : interfaces) {
            if (bond.getName().equals(i.getBondName())) {
                nics.add(i.getName());
            }
        }
        return nics;
    }

    private VdsNetworkInterface findNetworkInterface(String network,
            List<VdsNetworkInterface> interfaces,
            List<VdsNetworkInterface> bonds) {
        for (VdsNetworkInterface i : interfaces) {
            if (network.equals(i.getNetworkName())) {
                return i;
            }
        }

        for (VdsNetworkInterface i : bonds) {
            if (network.equals(i.getNetworkName())) {
                return i;
            }
        }

        return null;
    }

}

@@ -1713,48 +1713,211 @@
 ));%0A
-            String type = (i.getBonded()
+%0A            Boolean bonded = isVlan(net)%0A                    ? findInterfaceByName(NetworkUtils.StripVlan(i.getName())).getBonded()%0A                    : i.getBonded();%0A            String type = (bonded
  != 
@@ -1924,29 +1924,22 @@
 null && 
-i.getB
+b
 onded
-()
 ) ? %22bon
@@ -1953,17 +1953,16 @@
  %22nic%22;%0A
-%0A
         
@@ -2038,32 +2038,19 @@
 if (
-net.getvlan_id() != null
+isVlan(net)
 ) %7B%0A
@@ -2971,32 +2971,122 @@
 etworks;%0A    %7D%0A%0A
+    private boolean isVlan(network net) %7B%0A        return net.getvlan_id() != null;%0A    %7D%0A%0A
     private XmlR
@@ -5194,10 +5194,283 @@
 %0A    %7D%0A%0A
+    private VdsNetworkInterface findInterfaceByName(String name) %7B%0A        for (VdsNetworkInterface iface : getParameters().getInterfaces()) %7B%0A            if (name.equals(iface.getName())) %7B%0A                return iface;%0A            %7D%0A        %7D%0A%0A        return null;%0A    %7D%0A
 %7D%0A

Fix VLAN base iface type being sent to host