#import <Foundation/Foundation.h>

@interface Bar: NSObject 
-(void)wibble;
@end

@implementation Bar: NSObject
- (void)wibble
{
  NSLog(@"Wibble\n\n");
}
@end

@interface Foo : NSObject @end

//Redirect any unknown message the class receives to [Bar wibble]
@implementation Foo
- (NSMethodSignature*) methodSignatureForSelector: (SEL) aSel
{
  NSMethodSignature* sig;
  Bar* b = [[Bar new] autorelease];

  NSLog(@"Foo methodSignatureForSelector called with %@", NSStringFromSelector(aSel));

  sig = [b methodSignatureForSelector: @selector(wibble)];
  //Alternate test - even returning a null sig works in some cases
  //sig = [super methodSignatureForSelector: @selector(wibble)];
  NSLog(@"Returning sig %@", sig);
  return sig;
}

- (void)forwardInvocation: (NSInvocation*)inv
{
  NSLog(@"Foo - received %@ on %@ meta %d", inv,
  self, class_isMetaClass(object_getClass(self)));

  if(![NSStringFromSelector([inv selector]) isEqual: @"wibble"])
  {
    NSLog(@"Redirecting unknown method %@", NSStringFromSelector([inv selector]));
    [inv setSelector: @selector(wibble)];

  }

  [inv invokeWithTarget: [[Bar new] autorelease]];
}
@end

int main(void)
{
  CREATE_AUTORELEASE_POOL(pool);

  Foo *f= [Foo new];

  NSLog(@"First Test - Direct sending known method");
  [f wibble];

  NSLog(@"Second Test - performSelector with known method");
  [f performSelector: @selector(wibble)];

  NSLog(@"Third Test - performSelector with unknown method");
  [f performSelector: @selector(blah)];

  NSLog(@"Fourth Test - Direct sending unknown method");
  [f blah]; 

  NSLog(@"Fifth Test - performSelector with unknown method, after directly sending it");
  [f performSelector: @selector(blah)];

  RELEASE(pool);
  return 0;
}
