#import <Foundation/Foundation.h>

@interface Profiler : NSObject
{
	id target;
}
- (id)initWithObject:(id)aTarget;
- (void)setTarget:(id)aTarget;
@end

@implementation Profiler
- (id)initWithObject:(id)aTarget
{
	[super init];
	target = aTarget;
	return self;
}
- (id)init
{
	return [self initWithObject:nil];
}
- (void)setTarget:(id)aTarget
{
	target = aTarget;
	return;
}
- (void)profile:(NSInvocation *)anInvocation
{
	NSLog(@"start profiling [%@ %s]", [target className], [anInvocation selector]);
	NSDate *startTime = [NSDate date];
	[anInvocation invokeWithTarget:target];
	NSDate *endTime = [NSDate date];
	NSLog(@"finished!");
	NSLog(@"process time: %f (sec)", [endTime timeIntervalSinceDate:startTime]);
	return;
}
// メッセージ転送によって「対象の関数と同じ引数でプロファイル」を実現する
// Profilerの実装していないメッセージが来たら、
// 実行時間の計測をしつつ実際の処理はtargetに移譲
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
	if ([target respondsToSelector:aSelector])
		return [target methodSignatureForSelector:aSelector];
	else
		return [super methodSignatureForSelector:aSelector];
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
	if ([super respondsToSelector:aSelector])
		return YES;
	if ([self methodForSelector:aSelector] != (IMP)NULL)
		return YES;
	if ([target respondsToSelector:aSelector])
		return YES;
	return NO;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
	if ([target respondsToSelector:[anInvocation selector]])
	{
		[self profile:anInvocation];
	}
	else
	{
		[super forwardInvocation:anInvocation];
	}
	return;
}
//--- メッセージ転送処理ここまで
@end

@interface TestClass : NSObject
{
	NSTimeInterval interval;
}
- (void)func:(int)times;
@end

@implementation TestClass
- (id)init
{
	[super init];
	interval = 1.0;
	return self;
}
- (void)func:(int)times
{
	int i;
	for (i = 0; i < times; i++)
	{
		NSLog(@"一言言って%f秒待つことを%d回繰り返すだけの簡単なお仕事です", interval, times);
		[NSThread sleepForTimeInterval:interval];
		// Xcode 2.x だとスレッドのスリープはこっち
		// [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:interval]];
	}
}
@end

int main(int argc, const char *argv[])
{
	NSAutoreleasePool *pool = [NSAutoreleasePool new];
	
	id testTarget = [TestClass new];
	Profiler *profiler = [[Profiler alloc] initWithObject:testTarget];

	//profilerに本来testTargetが受けとるはずのメッセージを送ってやる
	[profiler func:3];

	[pool release];
	return 0;
}
