/* Interface for NSObject class
 *
 * Copyright (C)  1994  The Board of Trustees of  
 * The Leland Stanford Junior University.  All Rights Reserved.
 *
 * Author: Paul F. Kunz
 *
 * This file is part of an Objective-C class library
 *
 * Based on:
 * (Preliminary Documentation) Copyright (c) 1994 by NeXT Computer, Inc.  
 * All Rights Reserved.
 *
 * Original source copied from GNU implementation of Object
 *
 * NSObject.m,v 1.4 1995/03/28 23:56:11 fedor Exp
 */
 
 
#include "NSObject.h"

#include <objc/Protocol.h>

#ifdef __NeXT__
#include <objc/objc-class.h>
#endif

#include "NSString.h"
#include "zone.h"

#include <stdarg.h>
#include <stdio.h>

/* use the NeXT run-time if compiling on a NeXT with NeXT's cc */
#ifdef __NeXT__
#define class_get_class_method class_getClassMethod
#define class_get_instance_method class_getInstanceMethod
#define class_get_version class_getVersion
#define class_pose_as class_poseAs
#define class_set_version class_setVersion	
#define object_get_class_name object_getClassName
#define sel_get_name sel_getName

static inline Class
class_get_super_class(Class class)
{
  return CLS_GETINFO(class, CLS_CLASS)?class->super_class:Nil;
}

typedef struct objc_method *Method_t;
#define METHOD_NULL	(Method_t)0
static inline IMP
method_get_imp(Method_t method)
{
  return (method!=METHOD_NULL)?method->method_imp:(IMP)0;
}

static inline Class
object_get_class(id object)
{
  return ((object!=nil)
	  ? (CLS_GETINFO(object->isa, CLS_CLASS)
	     ? object->isa
	     : (CLS_GETINFO(object->isa, CLS_META)
		? (Class)object
		: Nil))
	  : Nil);
}

static inline Class
object_get_super_class
(id object)
{
  return ((object!=nil)? (CLS_GETINFO(object->isa, CLS_CLASS)
                         ? object->isa->super_class
			 : (CLS_GETINFO(object->isa, CLS_META)
                           ? ((Class)object)->super_class
                           : Nil))
                       : Nil);
}

static inline BOOL
object_is_instance(id object)
{
  return (object!=nil)&&CLS_GETINFO(object->isa, CLS_CLASS);
}

#endif	/* __NeXT__ */

extern void (*_objc_error)(id object, const char *format, va_list);

extern int errno;


@implementation NSObject

+ (void)initialize
{
  return;
}

+ (id)alloc
{
#ifdef __NeXT__
  return class_createInstance( self, 0 );
#else
  return class_create_instance( self );
#endif
}
 
+ (id)allocWithZone:(NSZone *)zone
{
#ifdef __NeXT__
  return class_createInstanceFromZone( self, 0, (NSZone *)zone );
#else  
  return [self alloc];	/* fake it */
#endif
}
  
+ (id)new
{
  return [[self alloc] init];
}
 
- (id)copy
{
#ifdef __NeXT__
  return object_copy( (Object *)self, 0);  /* even thou it's an NSObject */
#else
  return object_copy(self);
#endif
}
 
- (void)dealloc
{
  object_dispose( (id)self);
  return;
}
 
- (id)init
{
  return self;
}

- (id)mutableCopy
{
    return [self copy];	/* to be fixed when mutable is understood */
}

+ (Class)class
{
    return self;
}

+ (Class)superclass;
{
  return object_get_super_class(self);
}

- (NSZone *)zone
{
    return (NSZone *)0;
}
+ (BOOL)instancesRespondToSelector:(SEL)aSelector;
{
  return class_get_instance_method(self, aSelector)!=METHOD_NULL;
}

+ (BOOL)conformsToProtocol:(Protocol *)aProtocol;
{
  int i;
  struct objc_protocol_list* proto_list;

  for (proto_list = isa->protocols;
       proto_list; proto_list = proto_list->next)
    {
      for (i=0; i < proto_list->count; i++)
      {
        if ([proto_list->list[i] conformsTo: aProtocol])
          return YES;
      }
    }

  if ([self superclass])
    return [[self superclass] conformsTo: aProtocol];
  else
    return NO;
}

+ (IMP)instanceMethodForSelector:(SEL)aSelector;
{
  return method_get_imp(class_get_instance_method(self, aSelector));
}

- (IMP)methodForSelector:(SEL)aSelector;
{
  return (method_get_imp(object_is_instance(self)
                         ?class_get_instance_method(self->isa, aSelector)
                         :class_get_class_method(self->isa, aSelector)));
}
 
// - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
 /*
  * Returns an object that contains a description of the aSelector method, or
  * nil if the aSelector method can't be found. 
  */

+ (NSString *)description
{
  return [NSString stringWithCString:object_get_class_name(self)];
}

+ (void)poseAsClass:(Class)aClass
{
  class_pose_as(self,aClass);
  return;
}

- _error:(const char *)aString, ...
{
#define FMT "error: %s (%s)\n%s\n"
  char fmt[(strlen((char*)FMT)+strlen((char*)object_get_class_name(self))
            +((aString!=NULL)?strlen((char*)aString):0)+8)];
  va_list ap;

  sprintf(fmt, FMT, object_get_class_name(self),
                    object_is_instance(self)?"instance":"class",
                    (aString!=NULL)?aString:"");
  va_start(ap, aString);
//  (*_objc_error)(self, fmt, ap);
  vfprintf (stderr, fmt, ap);
  va_end(ap);
  return nil;
#undef FMT
}

- (void)doesNotRecognizeSelector:(SEL)aSelector;
{
  [self _error:"%s does not recognize %s",
                 object_get_class_name(self), sel_get_name(aSelector)];
  return;
}

// + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget
//        selector:(SEL)aSelector
//          object:(id)anObject;
 /*
  * Cancels previous perform requests having the same target and argument (as
  * determined by isEqual:), and the same selector.   This method removes
  * timers only in the current run loop, not all run loops. 
  */
		
// - (void)performSelector:(SEL)aSelector
//                 object:(id)anObject
//             afterDelay:(NSTimeInterval)delay
 /*
  * Sends an aSelector message to anObject after delay.  self and anObject
  * are retained until after the action is executed. 
  */

// - (void)forwardInvocation:(NSInvocation *)anInvocation
 /*
  * Implemented by subclasses to forward messages to other objects. 
  */

- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
{
  // [super awakeAfterUsingCoder:aDecoder];
  return self;
}
	
- (Class)classForArchiver
{
    return [self classForCoder];
}
 
- (Class)classForCoder
{
    return [self class];
}
 
- (id)replacementObjectForArchiver:(NSArchiver *)anArchiver
{
    return [self replacementObjectForCoder:(NSCoder *)anArchiver];
}

- (id)replacementObjectForCoder:(NSCoder *)anEncoder;
{
    return self;
}

+ (void)setVersion:(int)version;
{
  class_set_version(self, version);
  return;
}
 
+ (int)version;
{
  return class_get_version(self);
}
  
// @end

// @protocol NSObject

// NSObject protocol

- (unsigned)hash;
 /*
  * Returns an unsigned integer that can be used as a table address in a hash
  * table structure. Two objects that are equal must hash to the same value. 
  */
{
  return (size_t)self;	/* Is this right? */
}
 
- (BOOL)isEqual:(id)anObject;
 /*
  * Returns YES if the receiver and anObject have equal values; otherwise
  * returns NO. 
  */
{
  return self==anObject;	/* taken from GNU Object.m.   Is it right? */
}
 
- (id)self;
{
  return self;
}

- (Class)class;
{
  return object_get_class(self);
}

- (Class) superclass;
{
  return object_get_super_class(self);
}

- (id)perform:(SEL)aSelector
{
  IMP msg = [self methodForSelector:aSelector];

  if (!msg)
    return [self _error:"invalid selector passed to %s", sel_get_name(_cmd)];
  return (*msg)(self, aSelector);
}
 
- (id)perform:(SEL)aSelector
   withObject:(id)anObject;
{
  IMP msg = [self methodForSelector:aSelector];

  if (!msg)
    return [self _error:"invalid selector passed to %s", sel_get_name(_cmd)];
  return (*msg)(self, aSelector, anObject);
}
		
- (id)perform:(SEL)aSelector
   withObject:(id)anObject
   withObject:(id)anotherObject;
{
  IMP msg = [self methodForSelector:aSelector];

  if (!msg)
    return [self _error:"invalid selector passed to %s", sel_get_name(_cmd)];
  return (*msg)(self, aSelector, anObject, anotherObject);
}

// Identifying Proxies

- (BOOL)isProxy
{
    return NO;
}
 
- (BOOL)isKindOfClass:(Class)aClass
{
  Class class;

  for (class = self->isa; class!=Nil; class = class_get_super_class(class))
    if (class==aClass)
      return YES;
  return NO;
}
 
- (BOOL)isMemberOfClass:(Class)aClass
{
  return self->isa==aClass;
}

- (BOOL) conformsToProtocol: (Protocol *)aProtocol
{
  int i;
  struct objc_protocol_list* proto_list;

  for (proto_list = isa->protocols;
       proto_list; proto_list = proto_list->next)
    {
      for (i=0; i < proto_list->count; i++)
      {
        if ([proto_list->list[i] conformsTo: aProtocol])
          return YES;
      }
    }

  if ([self superclass])
    return [[self superclass] conformsToProtocol: aProtocol];
  else
    return NO;
}

- (BOOL)respondsToSelector:(SEL)aSelector;
{
  return ((object_is_instance(self)
           ?class_get_instance_method(self->isa, aSelector)
           :class_get_class_method(self->isa, aSelector))!=METHOD_NULL);
}

// - (id)autorelease
 /*
  * As defined in the NSObject class, decrements the receiver's reference
  * count. When the count reaches 0, adds the object to  the current
  * autorelease pool. Returns self. Objects in the pool are released later,
  * typically at the top of the event loop. 
  */
  
// - (oneway void)release;
 /*
  * As defined in the NSObject class, decrements the receiver's reference
  * count. When the count reaches 0, the object is automatically deallocated
  * immediately. 
  */
 
// - (id)retain;
 /*
  * As defined in the NSObject class, retain increments the receiver's
  * reference count. You send an object a retain message when you want to
  * prevent it from being deallocated without your express permission.
  * Returns self. 
  */
 
// - (unsigned)retainCount
 /*
  * Returns the receiver's reference count for debugging purposes. 
  */

- (NSString *)description;
{
  return [NSString stringWithCString:object_get_class_name(self)];
}


// NSCoding
// Serializing and Deserializing Objects

// @protocol NSCoding
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    return;
}
  
- (id)initWithCoder:(NSCoder *)aDecoder
{
    return self;
}

@end











