// Copyright 2015 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.

#ifndef PointerEventFactory_h
#define PointerEventFactory_h

#include "core/CoreExport.h"
#include "core/events/PointerEvent.h"
#include "public/platform/WebPointerProperties.h"
#include "wtf/Allocator.h"
#include "wtf/HashMap.h"

namespace blink {

/**
  Helper class for tracking the pointer ids for each type of PointerEvents.
  Using id re-mapping at this layer, this class makes sure that regardless of the
  domain of the id (i.e. in touch or pen) the corresponding pointer event will have
  a unique id amongst all pointer events as per pointer events' specification.
  This class intended to behave the same as existing browsers as much as possible
  for compatibility reasons. Particularly it behaves very similar to MS Edge to have
  pointer event ids generated by mouse always equal 1 and those that are generated
  by touch and pen will have increasing ids from 2.
*/
class CORE_EXPORT PointerEventFactory {
    DISALLOW_NEW();
public:

    PassRefPtrWillBeRawPtr<PointerEvent> create(const AtomicString& type,
        const PlatformMouseEvent&, PassRefPtrWillBeRawPtr<Node> relatedTarget,
        PassRefPtrWillBeRawPtr<AbstractView>);

    PassRefPtrWillBeRawPtr<PointerEvent> create(const AtomicString& type,
        const PlatformTouchPoint&, PlatformEvent::Modifiers,
        const double width, const double height,
        const double clientX, const double clientY);

    PassRefPtrWillBeRawPtr<PointerEvent> createPointerCancel(const PlatformTouchPoint&);

    PointerEventFactory();
    ~PointerEventFactory();

    // Clear all the existing ids.
    void clear();
    /*
     * When a pointerEvent with a particular id is removed that id is considered
     * free even though there might have been other PointerEvents that were
     * generated with the same id before.
     */
    void remove(const PassRefPtrWillBeRawPtr<PointerEvent>);

private:
    typedef long MappedId;
    typedef std::pair<int, int> IncomingId;

    MappedId add(const IncomingId);
    bool isPrimary(const MappedId) const;
    void setIdAndType(PointerEventInit &, const WebPointerProperties &);

    static const MappedId s_invalidId;
    static const MappedId s_mouseId;

    PointerEventFactory::MappedId m_currentId;
    HashMap<IncomingId, MappedId, WTF::PairHash<int, int>, WTF::PairHashTraits<WTF::UnsignedWithZeroKeyHashTraits<int>, WTF::UnsignedWithZeroKeyHashTraits<int>>> m_idMapping;
    HashMap<MappedId, IncomingId, WTF::IntHash<MappedId>, WTF::UnsignedWithZeroKeyHashTraits<MappedId>> m_idReverseMapping;
    MappedId m_primaryId[static_cast<int>(WebPointerProperties::PointerType::LastEntry) + 1];
    MappedId m_idCount[static_cast<int>(WebPointerProperties::PointerType::LastEntry) + 1];
};

} // namespace blink

#endif // PointerEventFactory_h
