/*
 * Copyright (C) 2013 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.
 */

#import "config.h"
#import "_WKRemoteObjectInterfaceInternal.h"

#if WK_API_ENABLED

#import <objc/runtime.h>
#import <wtf/HashMap.h>
#import <wtf/NeverDestroyed.h>
#import <wtf/Optional.h>
#import <wtf/RetainPtr.h>
#import <wtf/Vector.h>
#import <wtf/text/CString.h>

extern "C"
const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL sel, BOOL isRequiredMethod, BOOL isInstanceMethod);

@interface NSMethodSignature ()
- (NSMethodSignature *)_signatureForBlockAtArgumentIndex:(NSInteger)idx;
- (Class)_classForObjectAtArgumentIndex:(NSInteger)idx;
- (NSString *)_typeString;
@end

struct MethodInfo {
    Vector<HashSet<Class>> allowedArgumentClasses;

    struct ReplyInfo {
        NSUInteger replyPosition;
        CString replySignature;
        Vector<HashSet<Class>> allowedReplyClasses;
    };
    Optional<ReplyInfo> replyInfo;
};

@implementation _WKRemoteObjectInterface {
    RetainPtr<NSString> _identifier;

    HashMap<SEL, MethodInfo> _methods;
}

static bool isContainerClass(Class objectClass)
{
    // FIXME: Add more classes here if needed.
    static LazyNeverDestroyed<HashSet<Class>> containerClasses;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        containerClasses.construct(std::initializer_list<Class> { [NSArray class], [NSDictionary class] });
    });

    return containerClasses->contains(objectClass);
}

static HashSet<Class>& propertyListClasses()
{
    static LazyNeverDestroyed<HashSet<Class>> propertyListClasses;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        propertyListClasses.construct(std::initializer_list<Class> { [NSArray class], [NSDictionary class], [NSNumber class], [NSString class] });
    });

    return propertyListClasses;
}

static void initializeMethod(MethodInfo& methodInfo, Protocol *protocol, SEL selector, NSMethodSignature *methodSignature, bool forReplyBlock)
{
    Vector<HashSet<Class>> allowedClasses;

    NSUInteger firstArgument = forReplyBlock ? 1 : 2;
    NSUInteger argumentCount = methodSignature.numberOfArguments;

    bool foundBlock = false;
    for (NSUInteger i = firstArgument; i < argumentCount; ++i) {
        const char* argumentType = [methodSignature getArgumentTypeAtIndex:i];

        if (*argumentType != '@') {
            // This is a non-object type; we won't allow any classes to be decoded for it.
            allowedClasses.uncheckedAppend({ });
            continue;
        }

        if (*(argumentType + 1) == '?') {
            if (forReplyBlock)
                [NSException raise:NSInvalidArgumentException format:@"Blocks as arguments to the reply block of method (%s / %s) are not allowed", protocol_getName(protocol), sel_getName(selector)];

            if (foundBlock)
                [NSException raise:NSInvalidArgumentException format:@"Only one reply block is allowed per method (%s / %s)", protocol_getName(protocol), sel_getName(selector)];
            foundBlock = true;
            NSMethodSignature *blockSignature = [methodSignature _signatureForBlockAtArgumentIndex:i];
            ASSERT(blockSignature._typeString);

            methodInfo.replyInfo = MethodInfo::ReplyInfo();
            methodInfo.replyInfo->replyPosition = i;
            methodInfo.replyInfo->replySignature = blockSignature._typeString.UTF8String;

            initializeMethod(methodInfo, protocol, selector, blockSignature, true);
        }

        Class objectClass = [methodSignature _classForObjectAtArgumentIndex:i];
        if (!objectClass) {
            allowedClasses.append({ });
            continue;
        }

        if (isContainerClass(objectClass)) {
            // For container classes, we allow all simple property list classes.
            allowedClasses.append(propertyListClasses());
            continue;
        }

        allowedClasses.append({ objectClass });
    }

    if (forReplyBlock)
        methodInfo.replyInfo->allowedReplyClasses = WTF::move(allowedClasses);
    else
        methodInfo.allowedArgumentClasses = WTF::move(allowedClasses);
}

static void initializeMethods(_WKRemoteObjectInterface *interface, Protocol *protocol, bool requiredMethods)
{
    unsigned methodCount;
    struct objc_method_description *methods = protocol_copyMethodDescriptionList(protocol, requiredMethods, true, &methodCount);

    for (unsigned i = 0; i < methodCount; ++i) {
        SEL selector = methods[i].name;

        ASSERT(!interface->_methods.contains(selector));
        MethodInfo& methodInfo = interface->_methods.add(selector, MethodInfo()).iterator->value;

        const char* methodTypeEncoding = _protocol_getMethodTypeEncoding(protocol, selector, requiredMethods, true);
        if (!methodTypeEncoding)
            [NSException raise:NSInvalidArgumentException format:@"Could not find method type encoding for method \"%s\"", sel_getName(selector)];

        NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:methodTypeEncoding];

        initializeMethod(methodInfo, protocol, selector, methodSignature, false);
    }

    free(methods);
}

static void initializeMethods(_WKRemoteObjectInterface *interface, Protocol *protocol)
{
    unsigned conformingProtocolCount;
    Protocol** conformingProtocols = protocol_copyProtocolList(interface->_protocol, &conformingProtocolCount);

    for (unsigned i = 0; i < conformingProtocolCount; ++i) {
        Protocol* conformingProtocol = conformingProtocols[i];

        if (conformingProtocol == @protocol(NSObject))
            continue;

        initializeMethods(interface, conformingProtocol);
    }

    free(conformingProtocols);

    initializeMethods(interface, protocol, true);
    initializeMethods(interface, protocol, false);
}

- (id)initWithProtocol:(Protocol *)protocol identifier:(NSString *)identifier
{
    if (!(self = [super init]))
        return nil;

    _protocol = protocol;
    _identifier = adoptNS([identifier copy]);

    initializeMethods(self, _protocol);

    return self;
}

+ (instancetype)remoteObjectInterfaceWithProtocol:(Protocol *)protocol
{
    return [[[self alloc] initWithProtocol:protocol identifier:NSStringFromProtocol(protocol)] autorelease];
}

- (NSString *)identifier
{
    return _identifier.get();
}

- (NSString *)debugDescription
{
    auto result = adoptNS([[NSMutableString alloc] initWithFormat:@"<%@: %p; protocol = \"%@\"; identifier = \"%@\"\n", NSStringFromClass(self.class), self, _identifier.get(), NSStringFromProtocol(_protocol)]);

    auto descriptionForClasses = [](const Vector<HashSet<Class>>& allowedClasses) {
        auto result = adoptNS([[NSMutableString alloc] initWithString:@"["]);
        bool needsComma = false;

        auto descriptionForArgument = [](const HashSet<Class>& allowedArgumentClasses) {
            auto result = adoptNS([[NSMutableString alloc] initWithString:@"{"]);

            Vector<Class> orderedArgumentClasses;
            copyToVector(allowedArgumentClasses, orderedArgumentClasses);

            std::sort(orderedArgumentClasses.begin(), orderedArgumentClasses.end(), [](Class a, Class b) {
                return CString(class_getName(a)) < CString(class_getName(b));
            });

            bool needsComma = false;
            for (auto& argumentClass : orderedArgumentClasses) {
                if (needsComma)
                    [result appendString:@", "];

                [result appendFormat:@"%s", class_getName(argumentClass)];
                needsComma = true;
            }

            [result appendString:@"}"];
            return result.autorelease();
        };

        for (auto& argumentClasses : allowedClasses) {
            if (needsComma)
                [result appendString:@", "];

            [result appendString:descriptionForArgument(argumentClasses)];
            needsComma = true;
        }

        [result appendString:@"]"];
        return result.autorelease();
    };

    for (auto& selectorAndMethod : _methods) {
        [result appendFormat:@" selector = %s\n  argument classes = %@\n", sel_getName(selectorAndMethod.key), descriptionForClasses(selectorAndMethod.value.allowedArgumentClasses)];

        if (auto replyInfo = selectorAndMethod.value.replyInfo)
            [result appendFormat:@"  reply block = (argument #%lu '%s') %@\n", static_cast<unsigned long>(replyInfo->replyPosition), replyInfo->replySignature.data(), descriptionForClasses(replyInfo->allowedReplyClasses)];
    }

    [result appendString:@">\n"];
    return result.autorelease();
}

static HashSet<Class>& classesForSelectorArgument(_WKRemoteObjectInterface *interface, SEL selector, NSUInteger argumentIndex)
{
    auto it = interface->_methods.find(selector);
    if (it == interface->_methods.end())
        [NSException raise:NSInvalidArgumentException format:@"Interface does not contain selector \"%s\"", sel_getName(selector)];

    MethodInfo& methodInfo = it->value;
    auto& allowedArgumentClasses = methodInfo.allowedArgumentClasses;

    if (argumentIndex >= allowedArgumentClasses.size())
        [NSException raise:NSInvalidArgumentException format:@"Argument index %ld is out of range for selector \"%s\"", (unsigned long)argumentIndex, sel_getName(selector)];

    return allowedArgumentClasses[argumentIndex];
}

- (NSSet *)classesForSelector:(SEL)selector argumentIndex:(NSUInteger)argumentIndex
{
    auto result = adoptNS([[NSMutableSet alloc] init]);

    for (auto allowedClass : classesForSelectorArgument(self, selector, argumentIndex))
        [result addObject:allowedClass];

    return result.autorelease();
}

- (void)setClasses:(NSSet *)classes forSelector:(SEL)selector argumentIndex:(NSUInteger)argumentIndex
{
    HashSet<Class> allowedClasses;
    for (Class allowedClass in classes)
        allowedClasses.add(allowedClass);

    classesForSelectorArgument(self, selector, argumentIndex) = WTF::move(allowedClasses);
}

static const char* methodArgumentTypeEncodingForSelector(Protocol *protocol, SEL selector)
{
    // First look at required methods.
    struct objc_method_description method = protocol_getMethodDescription(protocol, selector, YES, YES);
    if (method.name)
        return method.types;

    // Then look at optional methods.
    method = protocol_getMethodDescription(protocol, selector, NO, YES);
    if (method.name)
        return method.types;

    return nullptr;
}

- (NSMethodSignature *)_methodSignatureForSelector:(SEL)selector
{
    if (!_methods.contains(selector))
        return nil;

    const char* types = methodArgumentTypeEncodingForSelector(_protocol, selector);
    if (!types)
        return nil;

    return [NSMethodSignature signatureWithObjCTypes:types];
}

- (NSMethodSignature *)_methodSignatureForReplyBlockOfSelector:(SEL)selector
{
    auto it = _methods.find(selector);
    if (it  == _methods.end())
        return nil;

    auto& methodInfo = it->value;
    if (!methodInfo.replyInfo)
        return nil;

    return [NSMethodSignature signatureWithObjCTypes:methodInfo.replyInfo->replySignature.data()];
}

- (const Vector<HashSet<Class>>&)_allowedArgumentClassesForSelector:(SEL)selector
{
    ASSERT(_methods.contains(selector));

    return _methods.find(selector)->value.allowedArgumentClasses;
}

- (const Vector<HashSet<Class>>&)_allowedArgumentClassesForReplyBlockOfSelector:(SEL)selector
{
    ASSERT(_methods.contains(selector));

    return _methods.find(selector)->value.replyInfo->allowedReplyClasses;
}

@end

#endif // WK_API_ENABLED
