/*
 * Read addresses of the parent interface and build a group of
 * corresponding networks.
 */
void AttachedNetworks::loadFromSource(bool ipv6, FWOptions*, bool)
{
    Interface *parent_intf = Interface::cast(getParent());
    assert(parent_intf);

    string c_type = (ipv6) ? IPv6::TYPENAME : IPv4::TYPENAME;

    // assemble list of address/netmask pairs to eliminate duplicates
    map<string, InetAddrMask> networks;

    FWObjectTypedChildIterator k = parent_intf->findByType(c_type);
    for ( ; k!=k.end(); ++k)
    {
        Address *addr = Address::cast(*k);
        const InetAddr *ip_netm = addr->getNetmaskPtr();
        const InetAddr *ip_net_addr = addr->getNetworkAddressPtr();
        ostringstream net;
        if (ip_net_addr->isV6())
        {
            net << ip_net_addr->toString() << "/" << ip_netm->getLength();
        } else
        {
            net << ip_net_addr->toString() << "/" << ip_netm->toString();
        }
        networks[net.str()] = InetAddrMask(*ip_net_addr, *ip_netm);
    }

    for (map<string, InetAddrMask>::iterator it=networks.begin(); it!=networks.end(); ++it)
    {
        addNetworkObject(it->second);
    }
}
/*
 * Call this after converting to atomic rules by DST to be sure there
 * is just one object in DST.
 */
bool RoutingCompiler::sameDestinationDifferentGateways::processNext()
{
    slurp();
    if (tmp_queue.size()==0) return false;

    // map destination to gateway.
    std::map<string, string> dst_to_gw;
    std::map<string, string> dst_to_rule;

    for (deque<Rule*>::iterator k=tmp_queue.begin(); k!=tmp_queue.end(); ++k)
    {
        RoutingRule *rule = RoutingRule::cast( *k );
        
        RuleElementRDst *dstrel = rule->getRDst();
        Address *dst = Address::cast(FWReference::getObject(dstrel->front()));
        const InetAddr* dst_addr = dst->getAddressPtr();
        const InetAddr* dst_netm = dst->getNetmaskPtr();
        string key = dst_addr->toString() + "/" + dst_netm->toString();

        // RuleElementRItf *itfrel = rule->getRItf();
        // FWObject *itf = FWReference::cast(itfrel->front())->getPointer();
    
        RuleElementRGtw *gtwrel = rule->getRGtw();
        Address *gtw = Address::cast(FWReference::getObject(gtwrel->front()));
        const InetAddr* gtw_addr = gtw->getAddressPtr();
        const InetAddr* gtw_netm = gtw->getNetmaskPtr();
        string val = gtw_addr->toString() + "/" + gtw_netm->toString();

        if (!dst_to_gw[key].empty() && dst_to_gw[key] != val)
        {
            compiler->abort(
                rule,
                "Rules " + dst_to_rule[key] + " and " + rule->getLabel() +
                " define routes to the same destination " + key +
                " via different gateways. This configuration is not supported"
                " for " + compiler->fw->getStr("host_OS"));
        } else
        {
            dst_to_gw[key] = val;
            dst_to_rule[key] = rule->getLabel();
        }
    }

    return true;
}
/*
 * checks if one of the children of RuleElement is a host, IPv4 or
 * network object with address 0.0.0.0 and netmask 0.0.0.0.
 *
 * Exceptions: 
 *   - object 'any'
 *   - interface with dynamic address.
 *
 * In addition check for address A.B.C.D/0 which is most likely a
 * mistake if A.B.C.D != 0.0.0.0. See #475
 */
Address* PolicyCompiler::checkForZeroAddr::findZeroAddress(RuleElement *re)
{
    Address *a=NULL;

    for (FWObject::iterator i=re->begin(); i!=re->end(); i++) 
    {
        FWObject *o = FWReference::getObject(*i);
	assert(o!=NULL);

        MultiAddress *maddr = MultiAddress::cast(o);
        if (maddr && maddr->isRunTime()) continue;

        Address *addr = Address::cast(o);
        
        if (addr==NULL && o!=NULL)
            compiler->warning(
                    re->getParent(), 
                    string("findZeroAddress: Unknown object in rule element: ") +
                    o->getName() +
                    "  type=" + o->getTypeName());

        if (addr && addr->hasInetAddress())
        {
            if (Interface::cast(o)!=NULL && 
                (Interface::cast(o)->isDyn() ||
                 Interface::cast(o)->isUnnumbered() ||
                 Interface::cast(o)->isBridgePort()))
                continue;

            if ( ! addr->isAny())
            {
                const InetAddr *ad = addr->getAddressPtr();
                const InetAddr *nm = addr->getNetmaskPtr();
                // AddressRange has address but not netmask
                // AddressRange with address 0.0.0.0 is acceptable
                // (not equivalent to "any")
                if (ad->isAny() && nm!=NULL && nm->isAny())
                {
                    a = addr;
                    break;
                }
                // Address A.B.C.D/0 is most likely a mistake if
                // A.B.C.D != 0.0.0.0
                if ((Network::cast(addr) || NetworkIPv6::cast(addr)) &&
                    !ad->isAny() && nm!=NULL && nm->isAny())
                {
                    a = addr;
                    break;
                }
            }
        }
    }

    return a;
}
InterfaceEditorWidget::InterfaceEditorWidget(QWidget *parent, Interface *iface) :
    QWidget(parent),
    m_ui(new Ui::InterfaceEditorWidget)
{
    tabw = dynamic_cast<QTabWidget*>(parent);
    this->interfacep = iface;
    m_ui->setupUi(this);
    setClusterMode(false);
    this->m_ui->name->setText(interfacep->getName().c_str());
    this->m_ui->label->setText(interfacep->getLabel().c_str());

//    if (iface->getPhysicalAddress() != NULL)
//       m_ui->mac->setText(iface->getPhysicalAddress()->getPhysAddress().c_str());

    this->m_ui->comment->setPlainText(iface->getComment().c_str());

    if ( this->interfacep->isDyn() ) this->m_ui->type->setCurrentIndex(1);
    if ( this->interfacep->isUnnumbered() ) this->m_ui->type->setCurrentIndex(2);

    FWObjectTypedChildIterator adriter = iface->findByType(IPv4::TYPENAME);
    for ( ; adriter != adriter.end(); ++adriter )
    {
        Address *addr = Address::cast(*adriter);
        int row = addNewAddress(addr->getAddressPtr()->toString().c_str(),
                                addr->getNetmaskPtr()->toString().c_str(),
                                addr->getAddressPtr()->isV4());
        fwaddrs[row] = addr;
    }
    FWObjectTypedChildIterator adriter2 = iface->findByType(IPv6::TYPENAME);
    for ( ; adriter2 != adriter2.end(); ++adriter2 )
    {
        Address *addr = Address::cast(*adriter2);
        int row = addNewAddress(addr->getAddressPtr()->toString().c_str(),
                                addr->getNetmaskPtr()->toString().c_str(),
                                addr->getAddressPtr()->isV4());
        fwaddrs[row] = addr;
    }
}
QString PIXObjectGroup::groupMemberToString(FWObject *obj,
                                           NamedObjectsManager*)
    throw(libfwbuilder::FWException)
{
    ostringstream ostr;

    if (this->getObjectGroupType() == NETWORK)
    {
        Address *a = Address::cast(obj);
        assert(a!=NULL);
        const InetAddr *addr = a->getAddressPtr();
        ostr << "network-object ";
        if (Network::cast(obj)!=NULL)
        {
            const InetAddr *mask = a->getNetmaskPtr();
            ostr << addr->toString() << " ";
            ostr << mask->toString() << " ";
        } else {
            ostr << "host ";
            ostr << addr->toString() << " ";
        }
        return ostr.str().c_str();

    } else
    {

        if (IPService::isA(obj))
        {
            ostr << "protocol-object ";
            Service *s=Service::cast(obj);
            assert(s!=NULL);
            ostr << s->getProtocolName();
            return ostr.str().c_str();
        }

        if (ICMPService::isA(obj))
        {
            ostr << "icmp-object ";
            ICMPService *s=ICMPService::cast(obj);
            assert(s!=NULL);
            if ( s->getInt("type")== -1)
                ostr << "any";
            else
                ostr << s->getInt("type");
            return ostr.str().c_str();
        }

        if (TCPService::isA(obj) || UDPService::isA(obj))
        {
            ostr << "port-object ";
            Service *s=Service::cast(obj);
            assert(s!=NULL);

            int rs=TCPUDPService::cast(s)->getDstRangeStart();
            int re=TCPUDPService::cast(s)->getDstRangeEnd();

            if (rs<0) rs=0;
            if (re<0) re=0;

            if (rs>0 || re>0) {
                if (rs==re)  ostr << "eq " << rs;
                else         ostr << "range " << rs << " " << re;
            }
            else ostr << "range 0 65535";
            return ostr.str().c_str();
        }

        QString err("PIXObjectGroup: Unsupported object '%1' found in "
                    "object group");
        throw FWException(err.arg(obj->getName().c_str()).toStdString());
    }

    return ostr.str().c_str();
}