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::_printRItf(RoutingRule *rule)
{
    FWObject *ref;
    
    RuleElementRItf *itfrel = rule->getRItf();
    ref = itfrel->front();
    Interface *itf = Interface::cast(FWReference::cast(ref)->getPointer());
    
    if (itf != NULL) return itf->getLabel() + " ";
    else return "";
}
string RoutingCompiler_iosacl::PrintRule::_printRItf(RoutingRule *rule)
{
    RuleElementRItf *itfrel = rule->getRItf();
    if (!itfrel->isAny())
    {
        Interface *itf =
            Interface::cast(FWObjectReference::getObject(itfrel->front()));
        if (itf != nullptr) return itf->getName() + " ";
    }
    return "";
}
bool RoutingCompiler::rItfChildOfFw::processNext()
{
    RoutingRule *rule=getNext(); if (rule==NULL) return false;
    tmp_queue.push_back(rule);
    
    RuleElementRItf *itfrel = rule->getRItf();

    if (itfrel->isAny()) return true;

    FWObject *o = FWReference::cast(itfrel->front())->getPointer();

    // the interface is not a child of the firewall. Could be
    // cluster interface though. In that case make sure the
    // firewall is a member of that cluster.
    Interface *iface = Interface::cast(o);
    if (iface)
    {
        FWObject *parent = Host::getParentHost(iface);
        //FWObject *parent = iface->getParentHost();
        if (parent->getId() == compiler->fw->getId()) return true;

        Cluster *cluster = Cluster::cast(parent);
        if (cluster)
        {            
            list<Firewall*> members;
            cluster->getMembersList(members);
            list<Firewall*>::iterator it;
            for (it=members.begin(); it!=members.end(); ++it)
            {
                if ((*it)->getId() == compiler->fw->getId()) return true;
            }
        }
    }
    string msg;
    msg = "Object \"" + o->getName() + 
        "\" used as interface in the routing rule " +
        rule->getLabel() +
        " is not a child of the firewall the rule belongs to";
    compiler->abort(rule, msg.c_str());
    // even though we call abort() here, it does not actually stop the
    // program if it runs in the test mode.
    return true;
}
bool RoutingCompiler::competingRules::processNext()
{
    RoutingRule *rule = getNext(); if (rule==NULL) return false;
        
    RuleElementRItf *itfrel = rule->getRItf();
    FWObject *itf = FWReference::cast(itfrel->front())->getPointer();
    
    RuleElementRGtw *gtwrel = rule->getRGtw();
    FWObject *gtw = FWReference::cast(gtwrel->front())->getPointer();
     
    string metric = rule->getMetricAsString();
    string label  = rule->getSortedDstIds();
    ostringstream ostr;
    ostr << gtw->getId() << "_" << itf->getId();
    string combiId = ostr.str();
    
    if( label == "") compiler->abort(
        
            rule,         
            "Place 'createSortedDstIdsLabel()' before 'competingRules()' "
            "in the rule processor chain");
    
    dest_it = rules_seen_so_far.find(label);
    if( dest_it != rules_seen_so_far.end()) {
        
        // a rule with the same destination was already seen
        ///std::cout << "NO NEW DEST" << std::endl;
        
        gtwitf_it = dest_it->second.find(combiId);
        if( gtwitf_it != dest_it->second.end() )
        {
            // ... this gateway and interface combination were already
            // seen for this destination
            ///std::cout << "NO NEW GTWITF" << std::endl;
            
            if( gtwitf_it->second.first == metric) {
                
                // ... and same metric => rule already exists, skip
                ///std::cout << "SAME METRIC" << std::endl;
                
                string msg;
                msg = "Routing rules " + gtwitf_it->second.second +
                    " and " + rule->getLabel() +
                    " are identical, skipping the second one. " +
                    "Delete one of them to avoid this warning";
                compiler->warning(rule,  msg.c_str());
            } else {
                
                // ... but different metric => what metric should I use? => abort
                ///std::cout << "DIFFERENT METRIC" << std::endl;
                
                string msg;
                msg = "Routing rules " + gtwitf_it->second.second +
                    " and " + rule->getLabel() +
                    " are identical except for the metric, " +
                    "please delete one of them";
                compiler->abort(rule,  msg.c_str());
            }
        
        } else
        {
            // ... this gateway and interface combination is new for
            // this destination
            ///std::cout << "NEW GTWITF" << std::endl;///
            
            if(false)
            {
                // TODO_lowPrio: if (
                // !compiler->fw->getOptionsObject()->getBool
                // ("equal_cost_multi_path") ) ...If multipath is
                // turned off, perform this check.

                // iterate all gtwitf combis in the map
                // dest_it->second and search for the current metric
                
                // ... but has the same metric => what route should I
                // use for this destination? => abort
                    
                string msg;
                msg = "Routing rules " + gtwitf_it->second.second + " and " +
                    rule->getLabel() +
                    " have the same destination and same metric,"
                    "but different gateway and interface combination. "
                    "Set the metrics to different values or "
                    "enable ECMP (Equal Cost MultiPath) routing";
                compiler->abort( msg.c_str() );
            
            } else
            {
                // ... and different metric OR equal_cost_multi_path enabled => OK
                tmp_queue.push_back(rule);
            }
            
            dest_it->second[combiId] =
                pair< string, string>( metric, rule->getLabel());
        }
        
    } else {
        
        // this destination is new
        //std::cout << "NEW DEST" << std::endl;
        ///
        
        //ruleinfo tmpRuleInfo = { gtw->getStr("id") + itf->getStr("id"), metric, rule->getLabel()};
        //rules_seen_so_far[label] = tmpRuleInfo;
        
        map< string, pair< string, string> > gtw_itf_tmp;
        gtw_itf_tmp[combiId] = pair< string, string>( metric, rule->getLabel());
        
        rules_seen_so_far[label] = gtw_itf_tmp;
        
        
        tmp_queue.push_back(rule);
    }

    return true;
}