/*
 * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
 * Copyright (C) 2011 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. ``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 "JSMessagePort.h"

#include "Event.h"
#include "ExceptionCode.h"
#include "Frame.h"
#include "JSDOMGlobalObject.h"
#include "JSEvent.h"
#include "JSEventListener.h"
#include "JSMessagePortCustom.h"
#include "MessagePort.h"
#include <runtime/Error.h>
#include <runtime/JSArrayBuffer.h>
#include <wtf/text/AtomicString.h>

using namespace JSC;

namespace WebCore {

void JSMessagePort::visitAdditionalChildren(SlotVisitor& visitor)
{
    // If we have a locally entangled port, we can directly mark it as reachable. Ports that are remotely entangled are marked in-use by markActiveObjectsForContext().
    if (MessagePort* port = wrapped().locallyEntangledPort())
        visitor.addOpaqueRoot(port);
}

JSC::JSValue JSMessagePort::postMessage(JSC::ExecState* exec)
{
    return handlePostMessage(exec, wrapped());
}

void extractTransferables(JSC::ExecState* exec, JSC::JSValue value, Vector<RefPtr<MessagePort>>& portArray, ArrayBufferArray& arrayBuffers)
{
    if (value.isUndefined()) {
        portArray.resize(0);
        arrayBuffers.resize(0);
        return;
    }

    VM& vm = exec->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    if (!value.isObject()) {
        throwSequenceTypeError(*exec);
        return;
    }

    struct Functor
    {
    	Functor(Vector<RefPtr<MessagePort>>& portArray, ArrayBufferArray& arrayBuffers)
    		: portArray(portArray)
    		, arrayBuffers(arrayBuffers)
    	{
    	}
    	void operator()(JSC::VM& vm, JSC::ExecState* exec, JSC::JSValue jsValue) {
            if (!jsValue.isObject()) {
                throwTypeError(exec, vm);
                return;
            }

            if(RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(jsValue)) {
    			if (arrayBuffer->isNeutered()) {
    				setDOMException(exec, DATA_CLONE_ERR);
    				return;
    			}
    			arrayBuffers.append(arrayBuffer.release());
    			return;
    		}

            if(RefPtr<MessagePort> port = toMessagePort(jsValue)) {
            	// FIXME: This should check if the port is detached as per https://html.spec.whatwg.org/multipage/infrastructure.html#istransferable.
    			portArray.append(port.release());
                return;
            }

    		setDOMException(exec, DATA_CLONE_ERR);
    		return;
		}
    	Vector<RefPtr<MessagePort>>& portArray;
    	ArrayBufferArray& arrayBuffers;
    };
    Functor functor(portArray, arrayBuffers);
    forEachInIterable(vm, *exec, value, functor);
}

} // namespace WebCore
