/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "cobalt/dom/event_target.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/debug/trace_event.h"
#include "base/message_loop.h"
#include "cobalt/dom/dom_exception.h"
#include "cobalt/dom/global_stats.h"

namespace cobalt {
namespace dom {

void EventTarget::AddEventListener(const std::string& type,
                                   const EventListenerScriptObject& listener,
                                   bool use_capture) {
  // Do nothing if listener is null.
  if (listener.IsNull()) {
    return;
  }

  EventListenerScriptObject::Reference listener_reference(this, listener);

  AddEventListenerInternal(base::Token(type), listener, use_capture,
                           EventListener::kNotAttribute);
}

void EventTarget::RemoveEventListener(const std::string& type,
                                      const EventListenerScriptObject& listener,
                                      bool use_capture) {
  // Do nothing if listener is null.
  if (listener.IsNull()) {
    return;
  }

  for (EventListenerInfos::iterator iter = event_listener_infos_.begin();
       iter != event_listener_infos_.end(); ++iter) {
    if ((*iter)->listener_type == EventListener::kNotAttribute &&
        (*iter)->type == type.c_str() &&
        (*iter)->listener.referenced_object().EqualTo(listener) &&
        (*iter)->use_capture == use_capture) {
      event_listener_infos_.erase(iter);
      return;
    }
  }
}

// Dispatch event to a single event target outside the DOM tree. The event
// propagation in the DOM tree is implemented inside Node::DispatchEvent().
bool EventTarget::DispatchEvent(const scoped_refptr<Event>& event,
                                script::ExceptionState* exception_state) {
  if (!event || event->IsBeingDispatched() || !event->initialized_flag()) {
    DOMException::Raise(DOMException::kInvalidStateErr, exception_state);
    // Return value will be ignored.
    return false;
  }

  return DispatchEvent(event);
}

bool EventTarget::DispatchEvent(const scoped_refptr<Event>& event) {
  DCHECK(event);
  DCHECK(!event->IsBeingDispatched());
  DCHECK(event->initialized_flag());
  TRACE_EVENT1("cobalt::dom", "EventTarget::DispatchEvent", "event",
               event->type().c_str());

  if (!event || event->IsBeingDispatched() || !event->initialized_flag()) {
    return false;
  }

  event->set_target(this);
  event->set_event_phase(Event::kAtTarget);
  FireEventOnListeners(event);
  event->set_event_phase(Event::kNone);
  return !event->default_prevented();
}

void EventTarget::DispatchEventAndRunCallback(
    base::Token event_name, const base::Closure& dispatched_callback) {
  DispatchEvent(make_scoped_refptr(new Event(event_name)));
  if (!dispatched_callback.is_null()) {
    dispatched_callback.Run();
  }
}

void EventTarget::PostToDispatchEvent(const tracked_objects::Location& location,
                                      base::Token event_name) {
  PostToDispatchEventAndRunCallback(location, event_name, base::Closure());
}

void EventTarget::PostToDispatchEventAndRunCallback(
    const tracked_objects::Location& location, base::Token event_name,
    const base::Closure& callback) {
  if (!MessageLoop::current()) {
    return;
  }
  MessageLoop::current()->PostTask(
      location,
      base::Bind(base::IgnoreResult(&EventTarget::DispatchEventAndRunCallback),
                 base::AsWeakPtr<EventTarget>(this), event_name, callback));
}

void EventTarget::SetAttributeEventListener(
    base::Token type, const EventListenerScriptObject& listener) {
  // Remove existing attribute listener of the same type.
  for (EventListenerInfos::iterator iter = event_listener_infos_.begin();
       iter != event_listener_infos_.end(); ++iter) {
    if ((*iter)->listener_type == EventListener::kAttribute &&
        (*iter)->type == type) {
      event_listener_infos_.erase(iter);
      break;
    }
  }

  if (listener.IsNull()) {
    return;
  }
  AddEventListenerInternal(type, listener, false, EventListener::kAttribute);
}

const EventTarget::EventListenerScriptObject*
EventTarget::GetAttributeEventListener(base::Token type) const {
  for (EventListenerInfos::const_iterator iter = event_listener_infos_.begin();
       iter != event_listener_infos_.end(); ++iter) {
    if ((*iter)->listener_type == EventListener::kAttribute &&
        (*iter)->type == type) {
      return &(*iter)->listener.referenced_object();
    }
  }
  return NULL;
}

bool EventTarget::ShouldKeepWrapperAlive() {
  return !event_listener_infos_.empty();
}

void EventTarget::FireEventOnListeners(const scoped_refptr<Event>& event) {
  DCHECK(event->IsBeingDispatched());
  DCHECK(event->target());
  DCHECK(!event->current_target());

  event->set_current_target(this);

  EventListenerInfos event_listener_infos;
  for (EventListenerInfos::iterator iter = event_listener_infos_.begin();
       iter != event_listener_infos_.end(); ++iter) {
    if ((*iter)->type == event->type()) {
      event_listener_infos.push_back(new EventListenerInfo(
          (*iter)->type, this, (*iter)->listener.referenced_object(),
          (*iter)->use_capture, (*iter)->listener_type));
    }
  }

  for (EventListenerInfos::iterator iter = event_listener_infos.begin();
       iter != event_listener_infos.end(); ++iter) {
    if (event->immediate_propagation_stopped()) {
      continue;
    }
    // Only call listeners marked as capture during capturing phase.
    if (event->event_phase() == Event::kCapturingPhase &&
        !(*iter)->use_capture) {
      continue;
    }
    // Don't call any listeners marked as capture during bubbling phase.
    if (event->event_phase() == Event::kBubblingPhase && (*iter)->use_capture) {
      continue;
    }
    (*iter)->listener.value().HandleEvent(event, (*iter)->listener_type);
  }

  event->set_current_target(NULL);
}

void EventTarget::AddEventListenerInternal(
    base::Token type, const EventListenerScriptObject& listener,
    bool use_capture, EventListener::Type listener_type) {
  DCHECK(!listener.IsNull());

  for (EventListenerInfos::iterator iter = event_listener_infos_.begin();
       iter != event_listener_infos_.end(); ++iter) {
    if ((*iter)->type == type &&
        (*iter)->listener.referenced_object().EqualTo(listener) &&
        (*iter)->use_capture == use_capture &&
        (*iter)->listener_type == listener_type) {
      // Attribute listeners should have already been removed.
      DCHECK_EQ(listener_type, EventListener::kNotAttribute);
      return;
    }
  }

  event_listener_infos_.push_back(
      new EventListenerInfo(type, this, listener, use_capture, listener_type));
}

EventTarget::EventListenerInfo::EventListenerInfo(
    base::Token type, EventTarget* const event_target,
    const EventListenerScriptObject& listener, bool use_capture,
    EventListener::Type listener_type)
    : type(type),
      listener(event_target, listener),
      use_capture(use_capture),
      listener_type(listener_type) {
  GlobalStats::GetInstance()->AddEventListener();
}

EventTarget::EventListenerInfo::~EventListenerInfo() {
  GlobalStats::GetInstance()->RemoveEventListener();
}

}  // namespace dom
}  // namespace cobalt
