// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/common/event_filter.h"

#include <string>
#include <utility>

#include "components/url_matcher/url_matcher_factory.h"
#include "ipc/ipc_message.h"

using url_matcher::URLMatcher;
using url_matcher::URLMatcherConditionSet;
using url_matcher::URLMatcherFactory;

namespace extensions {

EventFilter::EventMatcherEntry::EventMatcherEntry(
    std::unique_ptr<EventMatcher> event_matcher,
    URLMatcher* url_matcher,
    const URLMatcherConditionSet::Vector& condition_sets)
    : event_matcher_(std::move(event_matcher)), url_matcher_(url_matcher) {
  condition_set_ids_.reserve(condition_sets.size());
  for (const scoped_refptr<URLMatcherConditionSet>& condition_set :
       condition_sets) {
    condition_set_ids_.push_back(condition_set->id());
  }
  url_matcher_->AddConditionSets(condition_sets);
}

EventFilter::EventMatcherEntry::~EventMatcherEntry() {
  url_matcher_->RemoveConditionSets(condition_set_ids_);
}

void EventFilter::EventMatcherEntry::DontRemoveConditionSetsInDestructor() {
  condition_set_ids_.clear();
}

EventFilter::EventFilter()
    : next_id_(0),
      next_condition_set_id_(0) {
}

EventFilter::~EventFilter() {
  // Normally when an event matcher entry is removed from event_matchers_ it
  // will remove its condition sets from url_matcher_, but as url_matcher_ is
  // being destroyed anyway there is no need to do that step here.
  for (auto& matcher_map : event_matchers_) {
    for (auto& matcher : matcher_map.second)
      matcher.second->DontRemoveConditionSetsInDestructor();
  }
}

EventFilter::MatcherID EventFilter::AddEventMatcher(
    const std::string& event_name,
    std::unique_ptr<EventMatcher> matcher) {
  URLMatcherConditionSet::Vector condition_sets;
  if (!CreateConditionSets(matcher.get(), &condition_sets))
    return -1;

  MatcherID id = next_id_++;
  for (const scoped_refptr<URLMatcherConditionSet>& condition_set :
       condition_sets) {
    condition_set_id_to_event_matcher_id_.insert(
        std::make_pair(condition_set->id(), id));
  }
  id_to_event_name_[id] = event_name;
  event_matchers_[event_name][id] = std::make_unique<EventMatcherEntry>(
      std::move(matcher), &url_matcher_, condition_sets);
  return id;
}

EventMatcher* EventFilter::GetEventMatcher(MatcherID id) {
  const std::string& event_name = GetEventName(id);
  return event_matchers_[event_name][id]->event_matcher();
}

const std::string& EventFilter::GetEventName(MatcherID id) const {
  auto it = id_to_event_name_.find(id);
  DCHECK(it != id_to_event_name_.end());
  return it->second;
}

bool EventFilter::CreateConditionSets(
    EventMatcher* matcher,
    URLMatcherConditionSet::Vector* condition_sets) {
  int url_filter_count = matcher->GetURLFilterCount();
  if (url_filter_count == 0) {
    // If there are no URL filters then we want to match all events, so create a
    // URLFilter from an empty dictionary.
    base::DictionaryValue empty_dict;
    return AddDictionaryAsConditionSet(&empty_dict, condition_sets);
  }
  for (int i = 0; i < url_filter_count; i++) {
    base::DictionaryValue* url_filter;
    if (!matcher->GetURLFilter(i, &url_filter))
      return false;
    if (!AddDictionaryAsConditionSet(url_filter, condition_sets))
      return false;
  }
  return true;
}

bool EventFilter::AddDictionaryAsConditionSet(
    base::DictionaryValue* url_filter,
    URLMatcherConditionSet::Vector* condition_sets) {
  std::string error;
  URLMatcherConditionSet::ID condition_set_id = next_condition_set_id_++;
  condition_sets->push_back(URLMatcherFactory::CreateFromURLFilterDictionary(
      url_matcher_.condition_factory(),
      url_filter,
      condition_set_id,
      &error));
  if (!error.empty()) {
    LOG(ERROR) << "CreateFromURLFilterDictionary failed: " << error;
    url_matcher_.ClearUnusedConditionSets();
    condition_sets->clear();
    return false;
  }
  return true;
}

std::string EventFilter::RemoveEventMatcher(MatcherID id) {
  auto it = id_to_event_name_.find(id);
  std::string event_name = it->second;
  // EventMatcherEntry's destructor causes the condition set ids to be removed
  // from url_matcher_.
  event_matchers_[event_name].erase(id);
  id_to_event_name_.erase(it);
  return event_name;
}

std::set<EventFilter::MatcherID> EventFilter::MatchEvent(
    const std::string& event_name,
    const EventFilteringInfo& event_info,
    int routing_id) const {
  std::set<MatcherID> matchers;

  auto it = event_matchers_.find(event_name);
  if (it == event_matchers_.end())
    return matchers;

  const EventMatcherMap& matcher_map = it->second;
  const GURL& url_to_match_against =
      event_info.url ? *event_info.url : GURL::EmptyGURL();
  std::set<URLMatcherConditionSet::ID> matching_condition_set_ids =
      url_matcher_.MatchURL(url_to_match_against);
  for (const auto& id_key : matching_condition_set_ids) {
    auto matcher_id = condition_set_id_to_event_matcher_id_.find(id_key);
    if (matcher_id == condition_set_id_to_event_matcher_id_.end()) {
      NOTREACHED() << "id not found in condition set map (" << id_key << ")";
      continue;
    }
    MatcherID id = matcher_id->second;
    auto matcher_entry = matcher_map.find(id);
    if (matcher_entry == matcher_map.end()) {
      // Matcher must be for a different event.
      continue;
    }
    const EventMatcher* event_matcher = matcher_entry->second->event_matcher();
    // The context that installed the event listener should be the same context
    // as the one where the event listener is called.
    if (routing_id != MSG_ROUTING_NONE &&
        event_matcher->GetRoutingID() != routing_id) {
      continue;
    }
    if (event_matcher->MatchNonURLCriteria(event_info)) {
      CHECK(!event_matcher->HasURLFilters() || event_info.url);
      matchers.insert(id);
    }
  }

  return matchers;
}

int EventFilter::GetMatcherCountForEventForTesting(
    const std::string& name) const {
  auto it = event_matchers_.find(name);
  return it != event_matchers_.end() ? it->second.size() : 0;
}

}  // namespace extensions
