/*
 * Copyright (C) 2004 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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 "objc_class.h"

#include "objc_instance.h"
#include "WebScriptObject.h"

namespace JSC {
namespace Bindings {
    
static void deleteMethod(CFAllocatorRef, const void* value)
{
    delete static_cast<const Method*>(value);
}
    
static void deleteField(CFAllocatorRef, const void* value)
{
    delete static_cast<const Field*>(value);
}

const CFDictionaryValueCallBacks MethodDictionaryValueCallBacks = { 0, 0, &deleteMethod, 0 , 0 };
const CFDictionaryValueCallBacks FieldDictionaryValueCallBacks = { 0, 0, &deleteField, 0 , 0 };    
    
ObjcClass::ObjcClass(ClassStructPtr aClass)
    : _isa(aClass)
    , _methods(AdoptCF, CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &MethodDictionaryValueCallBacks))
    , _fields(AdoptCF, CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &FieldDictionaryValueCallBacks))
{
}

static CFMutableDictionaryRef classesByIsA = 0;

static void _createClassesByIsAIfNecessary()
{
    if (!classesByIsA)
        classesByIsA = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
}

ObjcClass* ObjcClass::classForIsA(ClassStructPtr isa)
{
    _createClassesByIsAIfNecessary();

    ObjcClass* aClass = (ObjcClass*)CFDictionaryGetValue(classesByIsA, isa);
    if (!aClass) {
        aClass = new ObjcClass(isa);
        CFDictionaryAddValue(classesByIsA, isa, aClass);
    }

    return aClass;
}

MethodList ObjcClass::methodsNamed(const Identifier& identifier, Instance*) const
{
    MethodList methodList;
    char fixedSizeBuffer[1024];
    char* buffer = fixedSizeBuffer;
    CString jsName = identifier.ascii();
    if (!convertJSMethodNameToObjc(jsName.data(), buffer, sizeof(fixedSizeBuffer))) {
        int length = jsName.length() + 1;
        buffer = new char[length];
        if (!buffer || !convertJSMethodNameToObjc(jsName.data(), buffer, length))
            return methodList;
    }

    
    RetainPtr<CFStringRef> methodName(AdoptCF, CFStringCreateWithCString(NULL, buffer, kCFStringEncodingASCII));
    Method* method = (Method*)CFDictionaryGetValue(_methods.get(), methodName.get());
    if (method) {
        methodList.append(method);
        return methodList;
    }

    ClassStructPtr thisClass = _isa;
    while (thisClass && methodList.isEmpty()) {
#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
        unsigned numMethodsInClass = 0;
        MethodStructPtr* objcMethodList = class_copyMethodList(thisClass, &numMethodsInClass);
#else
        void* iterator = 0;
        struct objc_method_list* objcMethodList;
        while ((objcMethodList = class_nextMethodList(thisClass, &iterator))) {
            unsigned numMethodsInClass = objcMethodList->method_count;
#endif
            for (unsigned i = 0; i < numMethodsInClass; i++) {
#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
                MethodStructPtr objcMethod = objcMethodList[i];
                SEL objcMethodSelector = method_getName(objcMethod);
#else
                struct objc_method* objcMethod = &objcMethodList->method_list[i];
                SEL objcMethodSelector = objcMethod->method_name;
#endif
                const char* objcMethodSelectorName = sel_getName(objcMethodSelector);
                NSString* mappedName = nil;

                // See if the class wants to exclude the selector from visibility in JavaScript.
                if ([thisClass respondsToSelector:@selector(isSelectorExcludedFromWebScript:)])
                    if ([thisClass isSelectorExcludedFromWebScript:objcMethodSelector])
                        continue;

                // See if the class want to provide a different name for the selector in JavaScript.
                // Note that we do not do any checks to guarantee uniqueness. That's the responsiblity
                // of the class.
                if ([thisClass respondsToSelector:@selector(webScriptNameForSelector:)])
                    mappedName = [thisClass webScriptNameForSelector:objcMethodSelector];

                if ((mappedName && [mappedName isEqual:(NSString*)methodName.get()]) || strcmp(objcMethodSelectorName, buffer) == 0) {
                    Method* aMethod = new ObjcMethod(thisClass, objcMethodSelector); // deleted when the dictionary is destroyed
                    CFDictionaryAddValue(_methods.get(), methodName.get(), aMethod);
                    methodList.append(aMethod);
                    break;
                }
            }
#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
            thisClass = class_getSuperclass(thisClass);
            free(objcMethodList);
#else
        }
        thisClass = thisClass->super_class;
#endif
    }

    if (buffer != fixedSizeBuffer)
        delete [] buffer;

    return methodList;
}

Field* ObjcClass::fieldNamed(const Identifier& identifier, Instance* instance) const
{
    ClassStructPtr thisClass = _isa;

    CString jsName = identifier.ascii();
    RetainPtr<CFStringRef> fieldName(AdoptCF, CFStringCreateWithCString(NULL, jsName.data(), kCFStringEncodingASCII));
    Field* aField = (Field*)CFDictionaryGetValue(_fields.get(), fieldName.get());
    if (aField)
        return aField;

    id targetObject = (static_cast<ObjcInstance*>(instance))->getObject();
    id attributes = [targetObject attributeKeys];
    if (attributes) {
        // Class overrides attributeKeys, use that array of key names.
        unsigned count = [attributes count];
        for (unsigned i = 0; i < count; i++) {
            NSString* keyName = [attributes objectAtIndex:i];
            const char* UTF8KeyName = [keyName UTF8String]; // ObjC actually only supports ASCII names.

            // See if the class wants to exclude the selector from visibility in JavaScript.
            if ([thisClass respondsToSelector:@selector(isKeyExcludedFromWebScript:)])
                if ([thisClass isKeyExcludedFromWebScript:UTF8KeyName])
                    continue;

            // See if the class want to provide a different name for the selector in JavaScript.
            // Note that we do not do any checks to guarantee uniqueness. That's the responsiblity
            // of the class.
            NSString* mappedName = nil;
            if ([thisClass respondsToSelector:@selector(webScriptNameForKey:)])
                mappedName = [thisClass webScriptNameForKey:UTF8KeyName];

            if ((mappedName && [mappedName isEqual:(NSString*)fieldName.get()]) || [keyName isEqual:(NSString*)fieldName.get()]) {
                aField = new ObjcField((CFStringRef)keyName); // deleted when the dictionary is destroyed
                CFDictionaryAddValue(_fields.get(), fieldName.get(), aField);
                break;
            }
        }
    } else {
        // Class doesn't override attributeKeys, so fall back on class runtime
        // introspection.

        while (thisClass) {
#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
            unsigned numFieldsInClass = 0;
            IvarStructPtr* ivarsInClass = class_copyIvarList(thisClass, &numFieldsInClass);
#else
            struct objc_ivar_list* fieldsInClass = thisClass->ivars;
            if (fieldsInClass) {
                unsigned numFieldsInClass = fieldsInClass->ivar_count;
#endif
                for (unsigned i = 0; i < numFieldsInClass; i++) {
#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
                    IvarStructPtr objcIVar = ivarsInClass[i];
                    const char* objcIvarName = ivar_getName(objcIVar);
#else
                    IvarStructPtr objcIVar = &fieldsInClass->ivar_list[i];
                    const char* objcIvarName = objcIVar->ivar_name;
#endif
                    NSString* mappedName = 0;

                    // See if the class wants to exclude the selector from visibility in JavaScript.
                    if ([thisClass respondsToSelector:@selector(isKeyExcludedFromWebScript:)])
                        if ([thisClass isKeyExcludedFromWebScript:objcIvarName])
                            continue;

                    // See if the class want to provide a different name for the selector in JavaScript.
                    // Note that we do not do any checks to guarantee uniqueness. That's the responsiblity
                    // of the class.
                    if ([thisClass respondsToSelector:@selector(webScriptNameForKey:)])
                        mappedName = [thisClass webScriptNameForKey:objcIvarName];

                    if ((mappedName && [mappedName isEqual:(NSString*)fieldName.get()]) || strcmp(objcIvarName, jsName.data()) == 0) {
                        aField = new ObjcField(objcIVar); // deleted when the dictionary is destroyed
                        CFDictionaryAddValue(_fields.get(), fieldName.get(), aField);
                        break;
                    }
                }
#if defined(OBJC_API_VERSION) && OBJC_API_VERSION >= 2
            thisClass = class_getSuperclass(thisClass);
            free(ivarsInClass);
#else
            }
            thisClass = thisClass->super_class;
#endif
        }
    }

    return aField;
}

JSValue ObjcClass::fallbackObject(ExecState* exec, Instance* instance, const Identifier &propertyName)
{
    ObjcInstance* objcInstance = static_cast<ObjcInstance*>(instance);
    id targetObject = objcInstance->getObject();
    
    if (![targetObject respondsToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)])
        return jsUndefined();
    return new (exec) ObjcFallbackObjectImp(exec, exec->lexicalGlobalObject(), objcInstance, propertyName);
}

}
}
