/*
 * Copyright (C) 2007, 2016 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. ``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
 * 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 "JSHTMLElement.h"

#include "CustomElementRegistry.h"
#include "DOMWindow.h"
#include "Document.h"
#include "HTMLFormElement.h"
#include "JSCustomElementInterface.h"
#include "JSDOMConstructorBase.h"
#include "JSNodeCustom.h"
#include "ScriptExecutionContext.h"
#include <JavaScriptCore/InternalFunction.h>
#include <JavaScriptCore/JSWithScope.h>

namespace WebCore {

using namespace JSC;

EncodedJSValue constructJSHTMLElement(JSGlobalObject* globalObject, ExecState& exec)
{
    VM& vm = globalObject->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    auto* jsConstructor = jsCast<JSDOMConstructorBase*>(exec.jsCallee());
    ASSERT(jsConstructor);

    auto* context = jsConstructor->scriptExecutionContext();
    if (!context)
        return throwConstructorScriptExecutionContextUnavailableError(exec, scope, "HTMLElement");
    ASSERT(context->isDocument());

    JSValue newTargetValue = exec.thisValue();
    auto* newTarget = newTargetValue.getObject();
    auto* newTargetGlobalObject = jsCast<JSDOMGlobalObject*>(newTarget->globalObject(vm));
    JSValue htmlElementConstructorValue = JSHTMLElement::getConstructor(vm, newTargetGlobalObject);
    if (newTargetValue == htmlElementConstructorValue)
        return throwVMTypeError(&exec, scope, "new.target is not a valid custom element constructor"_s);

    auto& document = downcast<Document>(*context);

    auto* window = document.domWindow();
    if (!window)
        return throwVMTypeError(&exec, scope, "new.target is not a valid custom element constructor"_s);

    auto* registry = window->customElementRegistry();
    if (!registry)
        return throwVMTypeError(&exec, scope, "new.target is not a valid custom element constructor"_s);

    auto* elementInterface = registry->findInterface(newTarget);
    if (!elementInterface)
        return throwVMTypeError(&exec, scope, "new.target does not define a custom element"_s);

    if (!elementInterface->isUpgradingElement()) {
        Structure* baseStructure = getDOMStructure<JSHTMLElement>(vm, *newTargetGlobalObject);
        auto* newElementStructure = InternalFunction::createSubclassStructure(&exec, newTargetValue, baseStructure);
        RETURN_IF_EXCEPTION(scope, encodedJSValue());

        Ref<HTMLElement> element = HTMLElement::create(elementInterface->name(), document);
        element->setIsDefinedCustomElement(*elementInterface);
        auto* jsElement = JSHTMLElement::create(newElementStructure, newTargetGlobalObject, element.get());
        cacheWrapper(newTargetGlobalObject->world(), element.ptr(), jsElement);
        return JSValue::encode(jsElement);
    }

    Element* elementToUpgrade = elementInterface->lastElementInConstructionStack();
    if (!elementToUpgrade) {
        throwTypeError(&exec, scope, "Cannot instantiate a custom element inside its own constructor during upgrades"_s);
        return JSValue::encode(jsUndefined());
    }

    JSValue elementWrapperValue = toJS(&exec, jsConstructor->globalObject(), *elementToUpgrade);
    ASSERT(elementWrapperValue.isObject());

    JSValue newPrototype = newTarget->get(&exec, vm.propertyNames->prototype);
    RETURN_IF_EXCEPTION(scope, encodedJSValue());

    JSObject* elementWrapperObject = asObject(elementWrapperValue);
    JSObject::setPrototype(elementWrapperObject, &exec, newPrototype, true /* shouldThrowIfCantSet */);
    RETURN_IF_EXCEPTION(scope, encodedJSValue());

    elementInterface->didUpgradeLastElementInConstructionStack();

    return JSValue::encode(elementWrapperValue);
}

JSScope* JSHTMLElement::pushEventHandlerScope(ExecState* exec, JSScope* scope) const
{
    HTMLElement& element = wrapped();

    // The document is put on first, fall back to searching it only after the element and form.
    // FIXME: This probably may use the wrong global object. If this is called from a native
    // function, then it would be correct but not optimal since the native function would *know*
    // the global object. But, it may be that globalObject() is more correct.
    // https://bugs.webkit.org/show_bug.cgi?id=134932
    VM& vm = exec->vm();
    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    
    scope = JSWithScope::create(vm, lexicalGlobalObject, scope, asObject(toJS(exec, globalObject(), element.document())));

    // The form is next, searched before the document, but after the element itself.
    if (HTMLFormElement* form = element.form())
        scope = JSWithScope::create(vm, lexicalGlobalObject, scope, asObject(toJS(exec, globalObject(), *form)));

    // The element is on top, searched first.
    return JSWithScope::create(vm, lexicalGlobalObject, scope, asObject(toJS(exec, globalObject(), element)));
}

} // namespace WebCore
