/*
 * Copyright (C) 2010 Apple Inc. All rights reserved.
 * Copyright (C) 2017 Sony Interactive Entertainment Inc.
 *
 * 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 "WebContextMenuProxyWin.h"

#if ENABLE(CONTEXT_MENUS)

#include "APIContextMenuClient.h"
#include "WebContextMenuItem.h"
#include "WebContextMenuItemData.h"
#include "WebPageProxy.h"
#include "WebProcessProxy.h"

namespace WebKit {
using namespace WebCore;

void WebContextMenuProxyWin::show()
{
    Vector<Ref<WebContextMenuItem>> proposedAPIItems;
    for (auto& item : m_context.menuItems())
        proposedAPIItems.append(WebContextMenuItem::create(item));
    m_contextMenuListener = WebContextMenuListenerProxy::create(this);
    m_page.contextMenuClient().getContextMenuFromProposedMenu(m_page, WTFMove(proposedAPIItems), *m_contextMenuListener, m_context.webHitTestResultData(), m_page.process().transformHandlesToObjects(m_userData.object()).get());
}

static HMENU createMenu(const ContextMenuContextData &context)
{
    HMENU menu = ::CreatePopupMenu();
    MENUINFO menuInfo;
    menuInfo.cbSize = sizeof(menuInfo);
    menuInfo.fMask = MIM_STYLE;
    menuInfo.dwStyle = MNS_NOTIFYBYPOS;
    menuInfo.dwMenuData = (ULONG_PTR)&context;
    ::SetMenuInfo(menu, &menuInfo);
    return menu;
}

static void populate(const ContextMenuContextData &, HMENU, const Vector<WebContextMenuItemData>&);

static void createMenuItem(const ContextMenuContextData &context, HMENU menu, const WebContextMenuItemData &data)
{
    UINT flags = 0;

    flags |= data.enabled() ? MF_ENABLED : MF_DISABLED;
    flags |= data.checked() ? MF_CHECKED : MF_UNCHECKED;

    switch (data.type()) {
    case ActionType:
    case CheckableActionType:
        ::AppendMenu(menu, flags | MF_STRING, data.action(), data.title().wideCharacters().data());
        break;
    case SeparatorType:
        ::AppendMenu(menu, flags | MF_SEPARATOR, data.action(), nullptr);
        break;
    case SubmenuType:
        HMENU submenu = createMenu(context);
        populate(context, submenu, data.submenu());
        ::AppendMenu(menu, flags | MF_POPUP, (UINT_PTR)submenu, data.title().wideCharacters().data());
        break;
    }
}

static void populate(const ContextMenuContextData &context, HMENU menu, const Vector<WebContextMenuItemData>& items)
{
    for (auto& data : items)
        createMenuItem(context, menu, data);
}

static void populate(const ContextMenuContextData &context, HMENU menu, const Vector<Ref<WebContextMenuItem>>& items)
{
    for (auto& item : items) {
        auto data = item->data();
        createMenuItem(context, menu, data);
    }
}

void WebContextMenuProxyWin::showContextMenuWithItems(Vector<Ref<WebContextMenuItem>>&& items)
{
    populate(m_context, m_menu, items);

    UINT flags = TPM_RIGHTBUTTON | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_HORIZONTAL | TPM_LEFTALIGN | TPM_HORPOSANIMATION;
    POINT pt { m_context.menuLocation().x(), m_context.menuLocation().y() };
    HWND wnd = m_page.viewWidget();
    ::ClientToScreen(wnd, &pt);
    ::TrackPopupMenuEx(m_menu, flags, pt.x, pt.y, m_page.viewWidget(), nullptr);
}

WebContextMenuProxyWin::WebContextMenuProxyWin(WebPageProxy& page, ContextMenuContextData&& context, const UserData& userData)
    : WebContextMenuProxy(WTFMove(context), userData)
    , m_page(page)
{
    m_menu = createMenu(m_context);
}

WebContextMenuProxyWin::~WebContextMenuProxyWin()
{
    if (m_menu)
        ::DestroyMenu(m_menu);
}

} // namespace WebKit
#endif // ENABLE(CONTEXT_MENUS)
