'Remove targets.
Remove non-priority targets that have only a single campaign or that
have enough inventory to satisfy all their campaigns. As a result may
end up removing campaigns if they\'re fully satisfied.'

def reduce_targets(self, campaigns, targets):

    campaign_names_by_target = defaultdict(list)
    for campaign in campaigns:
        for target_name in campaign.target_names:
            if (target_name not in self.priority_target_names):
                campaign_names_by_target[target_name].append(campaign.name)
    campaigns_by_name = {campaign.name: campaign for campaign in campaigns}
    targets_by_name = {target.name: target for target in targets}
    changed = False
    for (target_name, campaign_names) in campaign_names_by_target.iteritems():
        target = targets_by_name[target_name]
        campaign_impressions = sum((campaigns_by_name[name].impressions for name in campaign_names))
        fully_satisfied = (campaign_impressions <= target.impressions)
        single_campaign = (len(campaign_names) == 1)
        if (not (fully_satisfied or single_campaign)):
            continue
        changed = True
        for campaign_name in campaign_names:
            campaign = campaigns_by_name[campaign_name]
            if fully_satisfied:
                impressions = 0
            else:
                target_impressions = max(0, target.impressions)
                impressions = (campaign_impressions - target_impressions)
            target_names = campaign.target_names[:]
            target_names.remove(target_name)
            campaigns_by_name[campaign_name] = SimpleCampaign(campaign_name, target_names, impressions)
        del targets_by_name[target_name]
    reduced_campaigns = []
    for campaign in campaigns_by_name.itervalues():
        if (campaign.impressions > 0):
            reduced_campaigns.append(campaign)
    reduced_targets = targets_by_name.values()
    return (changed, reduced_campaigns, reduced_targets)
