/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "PointerLockController.h"

#if ENABLE(POINTER_LOCK)

#include "Chrome.h"
#include "ChromeClient.h"
#include "Element.h"
#include "Event.h"
#include "EventNames.h"
#include "Page.h"
#include "PlatformMouseEvent.h"
#include "RuntimeEnabledFeatures.h"
#include "UserGestureIndicator.h"
#include "VoidCallback.h"

namespace WebCore {

PointerLockController::PointerLockController(Page& page)
    : m_page(page)
{
}

void PointerLockController::requestPointerLock(Element* target)
{
    if (!target || !target->isConnected() || m_documentOfRemovedElementWhileWaitingForUnlock) {
        enqueueEvent(eventNames().pointerlockerrorEvent, target);
        return;
    }

    if (m_documentAllowedToRelockWithoutUserGesture != &target->document() && !UserGestureIndicator::processingUserGesture()) {
        enqueueEvent(eventNames().pointerlockerrorEvent, target);
        return;
    }

    if (target->document().isSandboxed(SandboxPointerLock)) {
        // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
        target->document().addConsoleMessage(MessageSource::Security, MessageLevel::Error, ASCIILiteral("Blocked pointer lock on an element because the element's frame is sandboxed and the 'allow-pointer-lock' permission is not set."));
        enqueueEvent(eventNames().pointerlockerrorEvent, target);
        return;
    }

    if (m_element) {
        if (&m_element->document() != &target->document()) {
            enqueueEvent(eventNames().pointerlockerrorEvent, target);
            return;
        }
        m_element = target;
        enqueueEvent(eventNames().pointerlockchangeEvent, target);
    } else {
        m_lockPending = true;
        m_element = target;
        if (!m_page.chrome().client().requestPointerLock()) {
            clearElement();
            enqueueEvent(eventNames().pointerlockerrorEvent, target);
        }
    }
}

void PointerLockController::requestPointerUnlock()
{
    if (!m_element)
        return;

    m_unlockPending = true;
    m_page.chrome().client().requestPointerUnlock();
}

void PointerLockController::requestPointerUnlockAndForceCursorVisible()
{
    m_documentAllowedToRelockWithoutUserGesture = nullptr;

    if (!m_element)
        return;

    m_unlockPending = true;
    m_page.chrome().client().requestPointerUnlock();
    m_forceCursorVisibleUponUnlock = true;
}

void PointerLockController::elementRemoved(Element& element)
{
    if (m_element == &element) {
        m_documentOfRemovedElementWhileWaitingForUnlock = &m_element->document();
        // Set element null immediately to block any future interaction with it
        // including mouse events received before the unlock completes.
        requestPointerUnlock();
        clearElement();
    }
}

void PointerLockController::documentDetached(Document& document)
{
    if (m_element && &m_element->document() == &document) {
        m_documentOfRemovedElementWhileWaitingForUnlock = &m_element->document();
        requestPointerUnlock();
        clearElement();
    }
}

bool PointerLockController::isLocked() const
{
    return m_element && !m_lockPending;
}

bool PointerLockController::lockPending() const
{
    return m_lockPending;
}

Element* PointerLockController::element() const
{
    return m_element.get();
}

void PointerLockController::didAcquirePointerLock()
{
    if (!m_lockPending)
        return;
    
    ASSERT(m_element);
    
    enqueueEvent(eventNames().pointerlockchangeEvent, m_element.get());
    m_lockPending = false;
    m_forceCursorVisibleUponUnlock = false;
    m_documentAllowedToRelockWithoutUserGesture = &m_element->document();
}

void PointerLockController::didNotAcquirePointerLock()
{
    enqueueEvent(eventNames().pointerlockerrorEvent, m_element.get());
    clearElement();
    m_unlockPending = false;
}

void PointerLockController::didLosePointerLock()
{
    if (!m_unlockPending)
        m_documentAllowedToRelockWithoutUserGesture = nullptr;

    enqueueEvent(eventNames().pointerlockchangeEvent, m_element ? &m_element->document() : m_documentOfRemovedElementWhileWaitingForUnlock.get());
    clearElement();
    m_unlockPending = false;
    m_documentOfRemovedElementWhileWaitingForUnlock = nullptr;
    if (m_forceCursorVisibleUponUnlock) {
        m_forceCursorVisibleUponUnlock = false;
        m_page.chrome().client().setCursorHiddenUntilMouseMoves(false);
    }
}

void PointerLockController::dispatchLockedMouseEvent(const PlatformMouseEvent& event, const AtomicString& eventType)
{
    if (!m_element || !m_element->document().frame())
        return;

    m_element->dispatchMouseEvent(event, eventType, event.clickCount());

    // Create click events
    if (eventType == eventNames().mouseupEvent)
        m_element->dispatchMouseEvent(event, eventNames().clickEvent, event.clickCount());
}

void PointerLockController::dispatchLockedWheelEvent(const PlatformWheelEvent& event)
{
    if (!m_element || !m_element->document().frame())
        return;

    m_element->dispatchWheelEvent(event);
}

void PointerLockController::clearElement()
{
    m_lockPending = false;
    m_element = nullptr;
}

void PointerLockController::enqueueEvent(const AtomicString& type, Element* element)
{
    if (element)
        enqueueEvent(type, &element->document());
}

void PointerLockController::enqueueEvent(const AtomicString& type, Document* document)
{
    if (document)
        document->enqueueDocumentEvent(Event::create(type, true, false));
}

} // namespace WebCore

#endif // ENABLE(POINTER_LOCK)
