/*
 * 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 "WebPluginScrollbarImpl.h"

#include "ScrollbarGroup.h"
#include "WebInputEvent.h"
#include "WebInputEventConversion.h"
#include "WebPluginContainerImpl.h"
#include "WebPluginScrollbarClient.h"
#include "WebViewImpl.h"
#include "core/platform/ScrollAnimator.h"
#include "core/platform/Scrollbar.h"
#include "core/platform/ScrollbarTheme.h"
#include "core/platform/chromium/KeyboardCodes.h"
#include "core/platform/graphics/GraphicsContext.h"
#include "platform/scroll/ScrollTypes.h"
#include "public/platform/WebCanvas.h"
#include "public/platform/WebRect.h"
#include "public/platform/WebVector.h"

using namespace std;
using namespace WebCore;

namespace blink {

WebPluginScrollbar* WebPluginScrollbar::createForPlugin(Orientation orientation,
                                                        WebPluginContainer* pluginContainer,
                                                        WebPluginScrollbarClient* client)
{
    WebPluginContainerImpl* plugin = toPluginContainerImpl(pluginContainer);
    return new WebPluginScrollbarImpl(orientation, plugin->scrollbarGroup(), client);
}

int WebPluginScrollbar::defaultThickness()
{
    return ScrollbarTheme::theme()->scrollbarThickness();
}

WebPluginScrollbarImpl::WebPluginScrollbarImpl(Orientation orientation,
                                   ScrollbarGroup* group,
                                   WebPluginScrollbarClient* client)
    : m_group(group)
    , m_client(client)
    , m_scrollOffset(0)
{
    m_scrollbar = Scrollbar::create(
        static_cast<ScrollableArea*>(m_group),
        static_cast<WebCore::ScrollbarOrientation>(orientation),
        WebCore::RegularScrollbar);
    m_group->scrollbarCreated(this);
}

WebPluginScrollbarImpl::~WebPluginScrollbarImpl()
{
    m_group->scrollbarDestroyed(this);
}

void WebPluginScrollbarImpl::setScrollOffset(int scrollOffset)
{
    m_scrollOffset = scrollOffset;
    m_client->valueChanged(this);
}

void WebPluginScrollbarImpl::invalidateScrollbarRect(const IntRect& rect)
{
    WebRect webrect(rect);
    webrect.x += m_scrollbar->x();
    webrect.y += m_scrollbar->y();
    m_client->invalidateScrollbarRect(this, webrect);
}

void WebPluginScrollbarImpl::getTickmarks(Vector<IntRect>& tickmarks) const
{
    WebVector<WebRect> ticks;
    m_client->getTickmarks(const_cast<WebPluginScrollbarImpl*>(this), &ticks);
    tickmarks.resize(ticks.size());
    for (size_t i = 0; i < ticks.size(); ++i)
        tickmarks[i] = ticks[i];
}

IntPoint WebPluginScrollbarImpl::convertFromContainingViewToScrollbar(const IntPoint& parentPoint) const
{
    IntPoint offset(parentPoint.x() - m_scrollbar->x(), parentPoint.y() - m_scrollbar->y());
    return m_scrollbar->Widget::convertFromContainingView(offset);
}

void WebPluginScrollbarImpl::scrollbarStyleChanged()
{
    m_client->overlayChanged(this);
}

bool WebPluginScrollbarImpl::isOverlay() const
{
    return m_scrollbar->isOverlayScrollbar();
}

int WebPluginScrollbarImpl::value() const
{
    return m_scrollOffset;
}

WebPoint WebPluginScrollbarImpl::location() const
{
    return m_scrollbar->frameRect().location();
}

WebSize WebPluginScrollbarImpl::size() const
{
    return m_scrollbar->frameRect().size();
}

bool WebPluginScrollbarImpl::enabled() const
{
    return m_scrollbar->enabled();
}

int WebPluginScrollbarImpl::maximum() const
{
    return m_scrollbar->maximum();
}

int WebPluginScrollbarImpl::totalSize() const
{
    return m_scrollbar->totalSize();
}

bool WebPluginScrollbarImpl::isScrollViewScrollbar() const
{
    return m_scrollbar->isScrollViewScrollbar();
}

bool WebPluginScrollbarImpl::isScrollableAreaActive() const
{
    return m_scrollbar->isScrollableAreaActive();
}

void WebPluginScrollbarImpl::getTickmarks(WebVector<WebRect>& tickmarks) const
{
    m_client->getTickmarks(const_cast<WebPluginScrollbarImpl*>(this), &tickmarks);
}

WebScrollbar::ScrollbarControlSize WebPluginScrollbarImpl::controlSize() const
{
    return static_cast<WebScrollbar::ScrollbarControlSize>(m_scrollbar->controlSize());
}

WebScrollbar::ScrollbarPart WebPluginScrollbarImpl::pressedPart() const
{
    return static_cast<WebScrollbar::ScrollbarPart>(m_scrollbar->pressedPart());
}

WebScrollbar::ScrollbarPart WebPluginScrollbarImpl::hoveredPart() const
{
    return static_cast<WebScrollbar::ScrollbarPart>(m_scrollbar->hoveredPart());
}

WebScrollbar::ScrollbarOverlayStyle WebPluginScrollbarImpl::scrollbarOverlayStyle() const
{
    return static_cast<WebScrollbar::ScrollbarOverlayStyle>(m_scrollbar->scrollbarOverlayStyle());
}

WebScrollbar::Orientation WebPluginScrollbarImpl::orientation() const
{
    if (m_scrollbar->orientation() == WebCore::HorizontalScrollbar)
        return WebScrollbar::Horizontal;
    return WebScrollbar::Vertical;
}

bool WebPluginScrollbarImpl::isLeftSideVerticalScrollbar() const
{
    return false;
}

bool WebPluginScrollbarImpl::isCustomScrollbar() const
{
    return m_scrollbar->isCustomScrollbar();
}

void WebPluginScrollbarImpl::setLocation(const WebRect& rect)
{
    IntRect oldRect = m_scrollbar->frameRect();
    m_scrollbar->setFrameRect(rect);
    if (WebRect(oldRect) != rect)
      m_scrollbar->invalidate();

    int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height();
    m_scrollbar->setEnabled(m_scrollbar->totalSize() > length);
    m_scrollbar->setProportion(length, m_scrollbar->totalSize());
}

void WebPluginScrollbarImpl::setValue(int position)
{
    m_group->scrollToOffsetWithoutAnimation(m_scrollbar->orientation(), static_cast<float>(position));
}

void WebPluginScrollbarImpl::setDocumentSize(int size)
{
    int length = m_scrollbar->orientation() == HorizontalScrollbar ? m_scrollbar->width() : m_scrollbar->height();
    m_scrollbar->setEnabled(size > length);
    m_scrollbar->setProportion(length, size);
}

void WebPluginScrollbarImpl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
{
    WebCore::ScrollDirection dir;
    bool horizontal = m_scrollbar->orientation() == HorizontalScrollbar;
    if (direction == ScrollForward)
        dir = horizontal ? ScrollRight : ScrollDown;
    else
        dir = horizontal ? ScrollLeft : ScrollUp;

    m_group->scroll(dir, static_cast<WebCore::ScrollGranularity>(granularity), multiplier);
}

void WebPluginScrollbarImpl::paint(WebCanvas* canvas, const WebRect& rect)
{
    GraphicsContext context(canvas);
    m_scrollbar->paint(&context, rect);
}

bool WebPluginScrollbarImpl::handleInputEvent(const WebInputEvent& event)
{
    switch (event.type) {
    case WebInputEvent::MouseDown:
        return onMouseDown(event);
    case WebInputEvent::MouseUp:
        return onMouseUp(event);
    case WebInputEvent::MouseMove:
        return onMouseMove(event);
    case WebInputEvent::MouseLeave:
        return onMouseLeave(event);
    case WebInputEvent::MouseWheel:
        return onMouseWheel(event);
    case WebInputEvent::KeyDown:
        return onKeyDown(event);
    case WebInputEvent::Undefined:
    case WebInputEvent::MouseEnter:
    case WebInputEvent::RawKeyDown:
    case WebInputEvent::KeyUp:
    case WebInputEvent::Char:
    case WebInputEvent::TouchStart:
    case WebInputEvent::TouchMove:
    case WebInputEvent::TouchEnd:
    case WebInputEvent::TouchCancel:
    default:
         break;
    }
    return false;
}

bool WebPluginScrollbarImpl::isAlphaLocked() const
{
    return m_scrollbar->isAlphaLocked();
}

void WebPluginScrollbarImpl::setIsAlphaLocked(bool flag)
{
    return m_scrollbar->setIsAlphaLocked(flag);
}

bool WebPluginScrollbarImpl::onMouseDown(const WebInputEvent& event)
{
    WebMouseEvent mousedown = *static_cast<const WebMouseEvent*>(&event);
    if (!m_scrollbar->frameRect().contains(mousedown.x, mousedown.y))
        return false;

    mousedown.x -= m_scrollbar->x();
    mousedown.y -= m_scrollbar->y();
    m_scrollbar->mouseDown(PlatformMouseEventBuilder(m_scrollbar.get(), mousedown));
    return true;
}

bool WebPluginScrollbarImpl::onMouseUp(const WebInputEvent& event)
{
    WebMouseEvent mouseup = *static_cast<const WebMouseEvent*>(&event);
    if (m_scrollbar->pressedPart() == WebCore::NoPart)
        return false;

    m_scrollbar->mouseUp(PlatformMouseEventBuilder(m_scrollbar.get(), mouseup));
    return true;
}

bool WebPluginScrollbarImpl::onMouseMove(const WebInputEvent& event)
{
    WebMouseEvent mousemove = *static_cast<const WebMouseEvent*>(&event);
    if (m_scrollbar->frameRect().contains(mousemove.x, mousemove.y)
        || m_scrollbar->pressedPart() != WebCore::NoPart) {
        mousemove.x -= m_scrollbar->x();
        mousemove.y -= m_scrollbar->y();
        m_scrollbar->mouseMoved(PlatformMouseEventBuilder(m_scrollbar.get(), mousemove));
        return true;
    }

    if (m_scrollbar->hoveredPart() != WebCore::NoPart && !m_scrollbar->isOverlayScrollbar())
        m_scrollbar->mouseExited();
    return false;
}

bool WebPluginScrollbarImpl::onMouseLeave(const WebInputEvent& event)
{
    if (m_scrollbar->hoveredPart() != WebCore::NoPart)
        m_scrollbar->mouseExited();

    return false;
}

bool WebPluginScrollbarImpl::onMouseWheel(const WebInputEvent& event)
{
    WebMouseWheelEvent mousewheel = *static_cast<const WebMouseWheelEvent*>(&event);
    PlatformWheelEventBuilder platformEvent(m_scrollbar.get(), mousewheel);
    return m_group->handleWheelEvent(platformEvent);
}

bool WebPluginScrollbarImpl::onKeyDown(const WebInputEvent& event)
{
    WebKeyboardEvent keyboard = *static_cast<const WebKeyboardEvent*>(&event);
    int keyCode;
    // We have to duplicate this logic from WebViewImpl because there it uses
    // Char and RawKeyDown events, which don't exist at this point.
    if (keyboard.windowsKeyCode == VKEY_SPACE)
        keyCode = ((keyboard.modifiers & WebInputEvent::ShiftKey) ? VKEY_PRIOR : VKEY_NEXT);
    else {
        if (keyboard.modifiers == WebInputEvent::ControlKey) {
            // Match FF behavior in the sense that Ctrl+home/end are the only Ctrl
            // key combinations which affect scrolling. Safari is buggy in the
            // sense that it scrolls the page for all Ctrl+scrolling key
            // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc.
            switch (keyboard.windowsKeyCode) {
            case VKEY_HOME:
            case VKEY_END:
                break;
            default:
                return false;
            }
        }

        if (keyboard.isSystemKey || (keyboard.modifiers & WebInputEvent::ShiftKey))
            return false;

        keyCode = keyboard.windowsKeyCode;
    }
    WebCore::ScrollDirection scrollDirection;
    WebCore::ScrollGranularity scrollGranularity;
    if (WebViewImpl::mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity)) {
        // Will return false if scroll direction wasn't compatible with this scrollbar.
        return m_group->scroll(scrollDirection, scrollGranularity);
    }
    return false;
}

} // namespace blink
