Пример #1
0
    //returns false if didn't get the intervention
    bool NodeLevelHealthTriggeredIV::notifyOnEvent(
        IIndividualHumanEventContext *pIndiv,
        const EventTrigger& trigger
    )
    {
        // ----------------------------------------------------------------------
        // --- Ignore events for nodes that don't qualify due to their properties
        // ----------------------------------------------------------------------
        if( !node_property_restrictions.Qualifies( parent->GetNodeContext()->GetNodeProperties() ) )
        {
            return false;
        }

        IIndividualHuman *p_human = nullptr;
        if (s_OK != pIndiv->QueryInterface(GET_IID(IIndividualHuman), (void**)&p_human))
        {
            throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "pIndiv", "IIndividualHuman", "IIndividualHumanEventContext" );
        }

        bool missed_intervention = false ;
        if( distribute_on_return_home && (trigger == EventTrigger::Emigrating) )
        {
            if( p_human->AtHome() )
            {
                // ------------------------------------------------------------------------------------------------
                // --- If the individual is leaving his node of residence, then we want to keep track that he left
                // --- so that when he returns we can give him the interventions that he missed.
                // ------------------------------------------------------------------------------------------------
                release_assert( event_occurred_while_resident_away.count( pIndiv->GetSuid() ) == 0 );
                event_occurred_while_resident_away.insert( make_pair( pIndiv->GetSuid(), false ) );
            }
            return false ;
        }
        else if( distribute_on_return_home && (trigger == EventTrigger::Immigrating) )
        {
            if( p_human->AtHome() )
            {
                // ------------------------------------------------------------------------------
                // --- If the individual has returned home and they missed the intervention, then
                // --- we want them to get it, assuming they qualify.
                // ------------------------------------------------------------------------------
                release_assert( event_occurred_while_resident_away.count( pIndiv->GetSuid() ) > 0 );
                missed_intervention = event_occurred_while_resident_away[ pIndiv->GetSuid() ] ;
                event_occurred_while_resident_away.erase( pIndiv->GetSuid() );
                if( missed_intervention )
                {
                    LOG_DEBUG_F( "Resident %d came home and intervention was distributed while away.\n", pIndiv->GetSuid().data );
                }
            }

            if( !missed_intervention )
            {
                return false ;
            }
        }
        else // the trigger event
        {
            // --------------------------------------------------------------------------------------------
            // --- If this is one of the non-migrating events that they intervention is listening for
            // --- and this is not a blackout period, then record that the residents that are away missed
            // --- the intervention.
            // --------------------------------------------------------------------------------------------
            if( blackout_time_remaining <= 0.0f )
            {
                for( auto& rEntry : event_occurred_while_resident_away )
                {
                    rEntry.second = true ;
                }
            }
        }

        if( !blackout_event_trigger.IsUninitialized() && (blackout_period > 0.0) )
        {
            if( (event_occured_list[ trigger.GetIndex() ].count( pIndiv->GetSuid().data ) > 0) || (!missed_intervention && (blackout_time_remaining > 0.0f)) )
            {
                INodeTriggeredInterventionConsumer * pNTIC = NULL;
                if (s_OK != parent->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&pNTIC) )
                {
                    throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent", "INodeTriggeredInterventionConsumer", "INodeEventContext" );
                }
                pNTIC->TriggerNodeEventObservers( pIndiv, blackout_event_trigger );
                return false;
            }
        }

        LOG_DEBUG_F("Individual %d experienced event %s, check to see if they pass the conditions before distributing actual_intervention \n",
                    pIndiv->GetInterventionsContext()->GetParent()->GetSuid().data,
                    trigger.c_str()
                   );

        assert( parent );
        assert( parent->GetRng() );

        bool distributed = false;
        if( _di != nullptr )
        {
            //initialize this flag by individual (not by node)
            m_disqualified_by_coverage_only = false;

            if( qualifiesToGetIntervention( pIndiv ) == false )
            {
                LOG_DEBUG_F("Individual failed to qualify for intervention, m_disqualified_by_coverage_only is %d \n", m_disqualified_by_coverage_only);
                if (m_disqualified_by_coverage_only == true)
                {
                    onDisqualifiedByCoverage( pIndiv );
                }
                return false;
            }

            // Query for campaign cost observer interface from INodeEventContext *parent
            ICampaignCostObserver *iCCO;
            if (s_OK != parent->QueryInterface(GET_IID(ICampaignCostObserver), (void**)&iCCO))
            {
                throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent", "ICampaignCostObserver", "INodeEventContext" );
            }

            // Huge performance win by cloning instead of configuring.
            IDistributableIntervention *di = _di->Clone();
            release_assert( di );
            di->AddRef();

            distributed = di->Distribute( pIndiv->GetInterventionsContext(), iCCO );
            if( distributed )
            {
                std::string classname = GetInterventionClassName();
                LOG_DEBUG_F("A Node level health-triggered intervention (%s) was successfully distributed to individual %d\n",
                            classname.c_str(),
                            pIndiv->GetInterventionsContext()->GetParent()->GetSuid().data
                           );
            }
            else
            {
                LOG_DEBUG_F( "Intervention not distributed?\n" );
            }
            di->Release();
        }
        else
        {
            release_assert( _ndi );

            // Huge performance win by cloning instead of configuring.
            INodeDistributableIntervention *ndi = _ndi->Clone();
            release_assert( ndi );
            ndi->AddRef();

            distributed =  ndi->Distribute( parent, nullptr );

            if( distributed )
            {
                std::string classname = GetInterventionClassName();
                LOG_INFO_F("Distributed '%s' intervention to node %d\n", classname.c_str(), parent->GetExternalId() );
            }
            ndi->Release();
        }

        if( distributed )
        {
            if( blackout_on_first_occurrence )
            {
                blackout_time_remaining = blackout_period ;
            }
            else
            {
                notification_occured = true ;
            }
            event_occured_list[ trigger.GetIndex() ].insert( pIndiv->GetSuid().data ); 
        }

        return distributed;
    }