/*
 * 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 KJS {
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;
}

const char* ObjcClass::name() const
{
    return object_getClassName(_isa);
}

MethodList ObjcClass::methodsNamed(const Identifier& identifier, Instance*) const
{
    MethodList methodList;
    char fixedSizeBuffer[1024];
    char* buffer = fixedSizeBuffer;
    const char* JSName = identifier.ascii();
    if (!convertJSMethodNameToObjc(JSName, buffer, sizeof(fixedSizeBuffer))) {
        int length = strlen(JSName) + 1;
        buffer = new char[length];
        if (!buffer || !convertJSMethodNameToObjc(JSName, 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, objcMethodSelectorName); // 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;

    const char* name = identifier.ascii();
    RetainPtr<CFStringRef> fieldName(AdoptCF, CFStringCreateWithCString(NULL, name, 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, name) == 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*, 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 ObjcFallbackObjectImp(objcInstance, propertyName);
}

}
}
