1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/sync/js_event_handler_list.h"
6
7#include <cstddef>
8
9#include "base/logging.h"
10#include "chrome/browser/sync/js_backend.h"
11#include "chrome/browser/sync/js_event_handler.h"
12
13namespace browser_sync {
14
15JsEventHandlerList::PendingMessage::PendingMessage(
16    const std::string& name, const JsArgList& args,
17    const JsEventHandler* sender)
18    : name(name), args(args), sender(sender) {}
19
20JsEventHandlerList::JsEventHandlerList() : backend_(NULL) {}
21
22JsEventHandlerList::~JsEventHandlerList() {
23  RemoveBackend();
24}
25
26// We connect to the backend only when necessary, i.e. when there is
27// at least one handler.
28
29void JsEventHandlerList::AddHandler(JsEventHandler* handler) {
30  handlers_.AddObserver(handler);
31  if (backend_) {
32    backend_->SetParentJsEventRouter(this);
33  }
34}
35
36void JsEventHandlerList::RemoveHandler(JsEventHandler* handler) {
37  handlers_.RemoveObserver(handler);
38  if (backend_ && handlers_.size() == 0) {
39    backend_->RemoveParentJsEventRouter();
40  }
41}
42
43void JsEventHandlerList::SetBackend(JsBackend* backend) {
44  DCHECK(!backend_);
45  DCHECK(backend);
46  backend_ = backend;
47
48  if (handlers_.size() > 0) {
49    backend_->SetParentJsEventRouter(this);
50
51    // Process any queued messages.
52    PendingMessageList pending_messages;
53    pending_messages_.swap(pending_messages);
54    for (PendingMessageList::const_iterator it = pending_messages.begin();
55         it != pending_messages.end(); ++it) {
56      backend_->ProcessMessage(it->name, it->args, it->sender);
57    }
58  }
59}
60
61void JsEventHandlerList::RemoveBackend() {
62  if (backend_) {
63    backend_->RemoveParentJsEventRouter();
64    backend_ = NULL;
65  }
66}
67
68void JsEventHandlerList::ProcessMessage(
69    const std::string& name, const JsArgList& args,
70    const JsEventHandler* sender) {
71  if (backend_) {
72    backend_->ProcessMessage(name, args, sender);
73  } else {
74    pending_messages_.push_back(PendingMessage(name, args, sender));
75  }
76}
77
78void JsEventHandlerList::RouteJsEvent(const std::string& name,
79                                      const JsArgList& args,
80                                      const JsEventHandler* target) {
81  if (target) {
82    JsEventHandler* non_const_target(const_cast<JsEventHandler*>(target));
83    if (handlers_.HasObserver(non_const_target)) {
84      non_const_target->HandleJsEvent(name, args);
85    } else {
86      VLOG(1) << "Unknown target; dropping event " << name
87              << " with args " << args.ToString();
88    }
89  } else {
90    FOR_EACH_OBSERVER(JsEventHandler, handlers_, HandleJsEvent(name, args));
91  }
92}
93
94}  // namespace browser_sync
95