/*
 * Copyright (C) 2011 Apple 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 "PluginTest.h"

#include "PluginObject.h"

using namespace std;

// NPP_SetWindow should be called with a null window handle as destruction begins on non-Mac platforms.

class NPPSetWindowCalledDuringDestruction : public PluginTest {
public:
    NPPSetWindowCalledDuringDestruction(NPP, const string& identifier);

    void setWillBeDestroyed() { m_willBeDestroyed = true; }

private:
    struct ScriptObject : Object<ScriptObject> {
        bool hasMethod(NPIdentifier);
        bool invoke(NPIdentifier, const NPVariant*, uint32_t, NPVariant*);
    };

    virtual NPError NPP_GetValue(NPPVariable, void*);
    virtual NPError NPP_SetWindow(NPP, NPWindow*);
    virtual NPError NPP_Destroy(NPSavedData**);

    bool m_willBeDestroyed;
    bool m_setWindowCalledBeforeDestruction;
    bool m_setWindowCalledDuringDestruction;
};

static PluginTest::Register<NPPSetWindowCalledDuringDestruction> registrar("npp-set-window-called-during-destruction");

NPPSetWindowCalledDuringDestruction::NPPSetWindowCalledDuringDestruction(NPP npp, const string& identifier)
    : PluginTest(npp, identifier)
    , m_willBeDestroyed(false)
    , m_setWindowCalledBeforeDestruction(false)
    , m_setWindowCalledDuringDestruction(false)
{
}

NPError NPPSetWindowCalledDuringDestruction::NPP_GetValue(NPPVariable variable, void* value)
{
    if (variable != NPPVpluginScriptableNPObject)
        return NPERR_GENERIC_ERROR;

    *static_cast<NPObject**>(value) = ScriptObject::create(this);

    return NPERR_NO_ERROR;
}

NPError NPPSetWindowCalledDuringDestruction::NPP_SetWindow(NPP, NPWindow* window)
{
    if (m_willBeDestroyed) {
        m_setWindowCalledDuringDestruction = true;
        if (!m_setWindowCalledBeforeDestruction) {
            log("Fail: setWillBeDestroyed() was called before the initial NPP_SetWindow call");
            return NPERR_NO_ERROR;
        }
#ifndef XP_MACOSX
        if (window->window)
            log("Fail: NPP_SetWindow passed a non-null window during plugin destruction");
#endif
        return NPERR_NO_ERROR;
    }

    if (m_setWindowCalledBeforeDestruction) {
        log("Fail: NPP_SetWindow called more than once before plugin destruction");
        return NPERR_NO_ERROR;
    }

    m_setWindowCalledBeforeDestruction = true;
    return NPERR_NO_ERROR;
}

NPError NPPSetWindowCalledDuringDestruction::NPP_Destroy(NPSavedData**)
{
#ifdef XP_MACOSX
    bool shouldHaveBeenCalledDuringDestruction = false;
#else
    bool shouldHaveBeenCalledDuringDestruction = true;
#endif

    if (m_setWindowCalledDuringDestruction == shouldHaveBeenCalledDuringDestruction)
        log("Success: NPP_SetWindow %s called during plugin destruction", shouldHaveBeenCalledDuringDestruction ? "was" : "was not");
    else
        log("Fail: NPP_SetWindow %s called during plugin destruction", shouldHaveBeenCalledDuringDestruction ? "was not" : "was");

    return NPERR_NO_ERROR;
}

bool NPPSetWindowCalledDuringDestruction::ScriptObject::hasMethod(NPIdentifier methodName)
{
    return methodName == pluginTest()->NPN_GetStringIdentifier("setWillBeDestroyed");
}

bool NPPSetWindowCalledDuringDestruction::ScriptObject::invoke(NPIdentifier identifier, const NPVariant*, uint32_t, NPVariant*)
{
    assert(identifier == pluginTest()->NPN_GetStringIdentifier("setWillBeDestroyed"));
    static_cast<NPPSetWindowCalledDuringDestruction*>(pluginTest())->setWillBeDestroyed();
    return true;
}
