/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "domstubs.idl"

%{C++
#include "nsEvent.h"
#include "mozilla/dom/Nullable.h"

using mozilla::dom::Nullable;

class nsPresContext;
class nsEventChainPreVisitor;
class nsEventChainPostVisitor;
struct JSContext;
class nsEventListenerManager;
%}

/**
 * The nsIDOMEventTarget interface is the interface implemented by all
 * event targets in the Document Object Model.
 *
 * For more information on this interface please see 
 * http://www.w3.org/TR/DOM-Level-2-Events/
 */

[ref] native nsEventChainPreVisitorRef(nsEventChainPreVisitor);
[ref] native nsEventChainPostVisitorRef(nsEventChainPostVisitor);
[ptr] native nsEventPtr(nsEvent);
[ptr] native nsPresContextPtr(nsPresContext);
[ptr] native nsEventStatusPtr(nsEventStatus);
[ptr] native JSContextPtr(JSContext);
[ptr] native nsEventListenerManagerPtr(nsEventListenerManager);

interface nsIScriptContext;
interface nsIDOMEventListener;
interface nsIDOMEvent;

[scriptable, builtinclass, uuid(8e375931-298d-4d0a-9cb4-5668f0cdc5a8)]
interface nsIDOMEventTarget : nsISupports
{
  /**
   * This method allows the registration of event listeners on the event target.
   * If an EventListener is added to an EventTarget while it is processing an
   * event, it will not be triggered by the current actions but may be 
   * triggered during a later stage of event flow, such as the bubbling phase.
   * 
   * If multiple identical EventListeners are registered on the same 
   * EventTarget with the same parameters the duplicate instances are 
   * discarded. They do not cause the EventListener to be called twice 
   * and since they are discarded they do not need to be removed with the 
   * removeEventListener method.
   *
   * @param   type The event type for which the user is registering
   * @param   listener The listener parameter takes an interface 
   *                   implemented by the user which contains the methods 
   *                   to be called when the event occurs.
   * @param   useCapture If true, useCapture indicates that the user 
   *                     wishes to initiate capture. After initiating 
   *                     capture, all events of the specified type will be 
   *                     dispatched to the registered EventListener before 
   *                     being dispatched to any EventTargets beneath them 
   *                     in the tree. Events which are bubbling upward 
   *                     through the tree will not trigger an 
   *                     EventListener designated to use capture.
   * @param   wantsUntrusted If false, the listener will not receive any
   *                         untrusted events (see above), if true, the
   *                         listener will receive events whether or not
   *                         they're trusted
   */
  [optional_argc] void addEventListener(in DOMString type,
                                        in nsIDOMEventListener listener,
                                        [optional] in boolean useCapture,
                                        [optional] in boolean wantsUntrusted);

  /**
   * addSystemEventListener() adds an event listener of aType to the system
   * group.  Typically, core code should use system group for listening to
   * content (i.e., non-chrome) element's events.  If core code uses
   * nsIDOMEventTarget::AddEventListener for a content node, it means
   * that the listener cannot listen the event when web content calls
   * stopPropagation() of the event.
   *
   * @param aType            An event name you're going to handle.
   * @param aListener        An event listener.
   * @param aUseCapture      TRUE if you want to listen the event in capturing
   *                         phase.  Otherwise, FALSE.
   * @param aWantsUntrusted  TRUE if you want to handle untrusted events.
   *                         Otherwise, FALSE.
   * @return                 NS_OK if succeed.  Otherwise, NS_ERROR_*.
   */
  [noscript, optional_argc] void addSystemEventListener(
                                   in DOMString type,
                                   in nsIDOMEventListener listener,
                                   [optional] in boolean aUseCapture,
                                   [optional] in boolean aWantsUntrusted);

%{C++
  // non-virtual so it won't affect the vtable
  nsresult AddEventListener(const nsAString& aType,
                            nsIDOMEventListener* aListener,
                            bool aUseCapture)
  {
    return AddEventListener(aType, aListener, aUseCapture, PR_FALSE, 1);
  }
  // non-virtual so it won't affect the vtable
  nsresult AddEventListener(const nsAString& aType,
                            nsIDOMEventListener* aListener,
                            bool aUseCapture,
                            bool aWantsUntrusted)
  {
    return AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted, 2);
  }
  // non-virtual so it won't affect the vtable
  nsresult AddSystemEventListener(const nsAString& aType,
                                  nsIDOMEventListener* aListener,
                                  bool aUseCapture)
  {
    return AddSystemEventListener(aType, aListener, aUseCapture, PR_FALSE, 1);
  }
  // non-virtual so it won't affect the vtable
  nsresult AddSystemEventListener(const nsAString& aType,
                                  nsIDOMEventListener* aListener,
                                  bool aUseCapture,
                                  bool aWantsUntrusted)
  {
    return AddSystemEventListener(aType, aListener, aUseCapture,
                                  aWantsUntrusted, 2);
  }
%}

  /**
   * This method allows the removal of event listeners from the event 
   * target. If an EventListener is removed from an EventTarget while it 
   * is processing an event, it will not be triggered by the current actions. 
   * EventListeners can never be invoked after being removed.
   * Calling removeEventListener with arguments which do not identify any 
   * currently registered EventListener on the EventTarget has no effect.
   *
   * @param   type Specifies the event type of the EventListener being 
   *               removed.
   * @param   listener The EventListener parameter indicates the 
   *                   EventListener to be removed.
   * @param   useCapture Specifies whether the EventListener being 
   *                     removed was registered as a capturing listener or 
   *                     not. If a listener was registered twice, one with 
   *                     capture and one without, each must be removed 
   *                     separately. Removal of a capturing listener does 
   *                     not affect a non-capturing version of the same 
   *                     listener, and vice versa.
   */
  void                     removeEventListener(in DOMString type,
                                               in nsIDOMEventListener listener,
                                               [optional] in boolean useCapture);

  /**
   * removeSystemEventListener() should be used if you have used
   * addSystemEventListener().
   */
  [noscript] void          removeSystemEventListener(
                             in DOMString type,
                             in nsIDOMEventListener listener,
                             [optional] in boolean aUseCapture);

  /**
   * This method allows the dispatch of events into the implementations 
   * event model. Events dispatched in this manner will have the same 
   * capturing and bubbling behavior as events dispatched directly by the 
   * implementation. The target of the event is the EventTarget on which 
   * dispatchEvent is called.
   *
   * @param   evt Specifies the event type, behavior, and contextual 
   *              information to be used in processing the event.
   * @return  Indicates whether any of the listeners which handled the 
   *          event called preventDefault. If preventDefault was called 
   *          the value is false, else the value is true.
   * @throws  INVALID_STATE_ERR: Raised if the Event's type was 
   *              not specified by initializing the event before 
   *              dispatchEvent was called. Specification of the Event's 
   *              type as null or an empty string will also trigger this 
   *              exception.
   */
  boolean                  dispatchEvent(in nsIDOMEvent evt)
                                               raises(DOMException);

  /**
   * Returns the nsPIDOMEventTarget object which should be used as the target
   * of DOMEvents.
   * Usually |this| is returned, but for example global object returns
   * the outer object.
   */
   [notxpcom, nostdcall] nsIDOMEventTarget GetTargetForDOMEvent();

  /**
   * Returns the nsPIDOMEventTarget object which should be used as the target
   * of the event and when constructing event target chain.
   * Usually |this| is returned, but for example global object returns
   * the inner object.
   */
   [notxpcom, nostdcall] nsIDOMEventTarget GetTargetForEventTargetChain();

  /**
   * Called before the capture phase of the event flow.
   * This is used to create the event target chain and implementations
   * should set the necessary members of nsEventChainPreVisitor.
   * At least aVisitor.mCanHandle must be set,
   * usually also aVisitor.mParentTarget if mCanHandle is PR_TRUE.
   * First one tells that this object can handle the aVisitor.mEvent event and
   * the latter one is the possible parent object for the event target chain.
   * @see nsEventDispatcher.h for more documentation about aVisitor.
   *
   * @param aVisitor the visitor object which is used to create the
   *                 event target chain for event dispatching.
   *
   * @note Only nsEventDispatcher should call this method.
   */
  [noscript, nostdcall]
  void PreHandleEvent(in nsEventChainPreVisitorRef aVisitor);

  /**
   * If nsEventChainPreVisitor.mWantsWillHandleEvent is set PR_TRUE,
   * called just before possible event handlers on this object will be called.
   */
  [noscript, nostdcall]
  void WillHandleEvent(in nsEventChainPostVisitorRef aVisitor);

  /**
   * Called after the bubble phase of the system event group.
   * The default handling of the event should happen here.
   * @param aVisitor the visitor object which is used during post handling.
   *
   * @see nsEventDispatcher.h for documentation about aVisitor.
   * @note Only nsEventDispatcher should call this method.
   */
  [noscript, nostdcall]
  void PostHandleEvent(in nsEventChainPostVisitorRef aVisitor);

  /**
   * Dispatch an event.
   * @param aEvent the event that is being dispatched.
   * @param aDOMEvent the event that is being dispatched, use if you want to
   *                  dispatch nsIDOMEvent, not only nsEvent.
   * @param aPresContext the current presentation context, can be nullptr.
   * @param aEventStatus the status returned from the function, can be nullptr.
   *
   * @note If both aEvent and aDOMEvent are used, aEvent must be the internal
   *       event of the aDOMEvent.
   *
   * If aDOMEvent is not nullptr (in which case aEvent can be nullptr) it is used
   * for dispatching, otherwise aEvent is used.
   *
   * @deprecated This method is here just until all the callers outside Gecko
   *             have been converted to use nsIDOMEventTarget::dispatchEvent.
   */
  [noscript, nostdcall]
  void DispatchDOMEvent(in nsEventPtr aEvent,
                        in nsIDOMEvent aDOMEvent,
                        in nsPresContextPtr aPresContext,
                        in nsEventStatusPtr aEventStatus);

  /**
   * Get the event listener manager, the guy you talk to to register for events
   * on this node.
   * @param aMayCreate If PR_FALSE, returns a listener manager only if
   *                   one already exists.
   */
  [notxpcom, nostdcall]
  nsEventListenerManagerPtr GetListenerManager(in boolean aMayCreate);

  /**
   * Get the script context in which the event handlers should be run.
   * May return null.
   * @note Caller *must* check the value of aRv.
   */
  [notxpcom, nostdcall]
  nsIScriptContext GetContextForEventHandlers(out nsresult aRv);

  /**
   * If the method above returns null, but a success code, this method
   * is called.
   */
  [notxpcom, nostdcall] JSContextPtr GetJSContextForEventHandlers();
};

%{C++

typedef nsIDOMEventTarget nsPIDOMEventTarget;

#define NS_IMPL_DOMTARGET_DEFAULTS(_class) \
nsPIDOMEventTarget* _class::GetTargetForDOMEvent() { return this; } \
nsPIDOMEventTarget* _class::GetTargetForEventTargetChain() { return this; } \
nsresult _class::WillHandleEvent(nsEventChainPostVisitor& aVisitor) { return NS_OK; } \
JSContext* _class::GetJSContextForEventHandlers() { return nullptr; }

#define NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(aClass) \
NS_IMETHODIMP \
aClass::RemoveSystemEventListener(const nsAString& aType, \
                                  nsIDOMEventListener *aListener, \
                                  bool aUseCapture) \
{ \
  nsEventListenerManager* listenerManager = GetListenerManager(false); \
  if (!listenerManager) { \
    return NS_OK; \
  } \
  uint32_t flags = NS_EVENT_FLAG_SYSTEM_EVENT; \
  flags |= aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE; \
  listenerManager->RemoveEventListenerByType(aListener, aType, flags); \
  return NS_OK; \
}

%}
