string RoutingCompiler_iosacl::PrintRule::RoutingRuleToString(RoutingRule *rule)
{
    FWObject *ref;

    RuleElementRDst *dstrel = rule->getRDst();
    ref = dstrel->front();
    Address *dst = Address::cast(FWReference::cast(ref)->getPointer());
    if(dst == nullptr) compiler->abort(rule, "Broken DST");

    std::ostringstream command_line;

    command_line << "ip route ";
    command_line << _printRDst(rule);
    command_line << _printRGtw(rule);
    command_line << _printRItf(rule);

    // default metric in IOS is 1 (can't have metric 0)
    if (rule->getMetricAsString() == "0")
    {
        command_line << "1";
    } else {
        command_line << rule->getMetricAsString();
    }

    command_line << endl;

    return command_line.str();
}
string RoutingCompiler::debugPrintRule(Rule *r)
{
    RoutingRule *rule = RoutingRule::cast(r);

    RuleElementRDst *dstrel = rule->getRDst();
    RuleElementRItf *itfrel = rule->getRItf();
    RuleElementRGtw *gtwrel = rule->getRGtw();

    ostringstream str;

//    str << setw(70) << setfill('-') << "-";

    string dst, itf, gtw;
   
    FWObject *obj = FWReference::getObject(itfrel->front());
    itf = (obj) ? obj->getName() : "NULL";

    obj = FWReference::getObject(gtwrel->front());
    gtw = (obj) ? obj->getName() : "NULL";
     
    
    int no = 0;
    FWObject::iterator i1 = dstrel->begin();
    while ( i1!=dstrel->end())
    {
        str << endl;

        dst = " ";

        if (i1 != dstrel->end())
        {
            FWObject *o = FWReference::getObject(*i1);
            dst = (o) ? o->getName() : "NULL";
        }

        int w = 0;
        if (no==0)
        {
            str << rule->getLabel();
            w = rule->getLabel().length();
        }
        
        str <<  setw(10-w)  << setfill(' ') << " ";

        str <<  setw(18) << setfill(' ') << dst.c_str() << " ";
        str <<  setw(18) << setfill(' ') << itf.c_str() << " ";
        str <<  setw(18) << setfill(' ') << gtw.c_str() << " ";
        str <<  setw(18) << setfill(' ') << " ";

        ++no;

        if ( i1 != dstrel->end() ) ++i1;
    }
    return str.str();
}
string RoutingCompiler_cisco::PrintRule::_printRDst(RoutingRule *rule)
{
    FWObject *ref;
    
    RuleElementRDst *dstrel = rule->getRDst();
    ref = dstrel->front();
    Address *dst = Address::cast(FWReference::cast(ref)->getPointer());
    if (dst==NULL) compiler->abort(rule, "Broken DST");
    
    string dest = _printAddr(dst);

    if (dest != "default ") return dest;
    else return "0.0.0.0 0.0.0.0 ";
}
bool RoutingCompiler_openbsd::FindDefaultRoute::processNext()
{
    RoutingCompiler_openbsd *bsd_comp = dynamic_cast<RoutingCompiler_openbsd*>(compiler);
    RoutingRule *rule;
    rule=getNext(); if (rule==NULL) return false;

    RuleElementRDst *dstrel = rule->getRDst();
    FWObject *ref = dstrel->front();
    Address *dst = Address::cast(FWReference::cast(ref)->getPointer());
    if (dst->isAny()) bsd_comp->have_default_route = true;

    tmp_queue.push_back(rule);
    return true;
}
/*
 * 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;
}