/*
 * Ticket #727
 *
 * if type is ethernet and has vlan subinterfaces, not eligible
 * if type is vlan, eligible
 * if type is bridge, eligible
 * if type is bonding, eligible
 * if type is ethernet and interface with the same name is used for bonding, then not eligible
 * if type is ethernet and parent is bridge, then not eligible
 */
bool interfaceProperties::isEligibleForCluster(Interface *intf)
{
    list<FWObject*> subinterfaces = intf->getByType(Interface::TYPENAME);
    string interface_type = intf->getOptionsObject()->getStr("type");

    if (intf->isBridgePort())
        return false;

    if (interface_type.empty())
        interface_type = "ethernet";
    if (interface_type == "8021q")
        return true;
    if (interface_type == "bridge")
        return true;
    if (interface_type == "bonding")
        return true;

    if (interface_type == "ethernet")
    {
        Interface *parent_iface = Interface::cast(intf->getParent());
        if (parent_iface &&
            parent_iface->getOptionsObject()->getStr("type") == "bridge")
            return false;

        FWObject *fw = Host::getParentHost(intf);
        //FWObject *fw = intf->getParentHost();
        list<FWObject*> interfaces = fw->getByTypeDeep(Interface::TYPENAME);
        list<FWObject*>::iterator i;
        for (i=interfaces.begin(); i!=interfaces.end(); ++i )
        {
            Interface *iface = Interface::cast(*i);
            assert(iface);
            Interface *parent_iface = Interface::cast(iface->getParent());
            if (parent_iface == nullptr)
         continue;
            if (parent_iface->getOptionsObject()->getStr("type") == "bonding" &&
                iface->getName() == intf->getName())
            {
                // @intf is used as a bond slave and can't be used for cluster
                return false;
            }

        }

        if (subinterfaces.size() > 0)
            return false;
    }
    return true;
}
/*
 * we manage only addresses of vrrp cluster interfaces.
 *
 * We ignore addresses of heartbeat and openais cluster interfaces.
 * To ignore them, we pass list of addresses managed by heartbeat to
 * shell function update_addresses (defined in configlet
 * "update_addresses") as its second argument to make it ignore these
 *
 * This code assumes the name of the cluster interface is the same as
 * names of the corresponding interfaces of member firewalls.
 */
bool interfaceProperties::manageIpAddresses(Interface *intf,
                                            QStringList &update_addresses,
                                            QStringList &ignore_addresses)
{
    update_addresses.clear();
    ignore_addresses.clear();

    FWObject *fw = Host::getParentHost(intf);
    //FWObject *fw = intf->getParentHost();
    Resources *os_res = Resources::os_res[fw->getStr("host_OS")];
    assert(os_res != nullptr);

    if (intf->isDyn()) return false;
    if (intf->isBridgePort()) return false;
    if (intf->isSlave()) return false;
    if (intf->isUnnumbered()) return false;   // see #1506

    string intf_name = intf->getName();

    if (intf->getOptionsObject()->getBool("cluster_interface"))
    {
        if (intf->isLoopback()) return false;

        if (intf->isFailoverInterface())
        {
            FWObject *failover_group =
                intf->getFirstByType(FailoverClusterGroup::TYPENAME);
            string failover_type = failover_group->getStr("type");

            if (os_res->getResourceBool(
                    "/FWBuilderResources/Target/protocols/" + failover_type + "/manage_addresses"))
            {
                getListOfAddresses(intf, update_addresses);
                return true;
            } else
                return false;
        }

        /*
         * if this is cluster interface with the same name as fw interface
         * (as happens in case of hearbeat or openais), skip it
         */
        if (intf->getOptionsObject()->getStr("base_device") == intf_name)
            return false;
    } else
    {
        // regular interface. Lets see if there is cluster interface
        // with the same name. If there is and its failover protocol
        // is heartbeat or openais, we should ignore all addresses it
        // might have.

        getListOfAddresses(intf, update_addresses);

        list<FWObject*> interfaces = fw->getByTypeDeep(Interface::TYPENAME);
        list<FWObject*>::iterator i;
        for (i=interfaces.begin(); i!=interfaces.end(); ++i )
        {
            Interface *iface = Interface::cast(*i);
            assert(iface);

            if (iface->getName() == intf_name &&
                iface->getOptionsObject()->getBool("cluster_interface") &&
                iface->isFailoverInterface())
            {
                FWObject *failover_group =
                    iface->getFirstByType(FailoverClusterGroup::TYPENAME);
                string failover_type = failover_group->getStr("type");

                // some protocols do not like it when failover ip address
                // is managed outside their software
                if (! os_res->getResourceBool(
                        "/FWBuilderResources/Target/protocols/" + failover_type + "/manage_addresses"))
                    getListOfAddresses(iface, ignore_addresses);
                break;
            }
        }
    }

    return true;
}