//
//  AfficheurService.m
//  Afficheur
//
//  Created by kichi on 08/11/23.
//  Copyright 2008 Katsuhiko Ichinose. All rights reserved.
//

#import "AfficheurService.h"
#import "AfficheurController.h"
#import "AfficheurPreferences.h"
#import "ServiceTwitter.h"
#import "ServiceJaiku.h"
#import "ServiceTumblr.h"
//#import "ServiceNowa.h"
#import "ServiceWassr.h"
#import "ServiceIdentica.h"
//#import "ServiceJisko.h"
//#import "ServiceChuitter.h"
#import "ServiceFriendFeed.h"
#import "ServiceFaceBook.h"
#import "ServiceXMPP.h"

@implementation AfficheurService

NSString*	KeyTimelineCommand		= @"command";
NSString*	KeyTimelineService		= @"service";
NSString*	KeyTimelineObject		= @"object";

NSString*	CmdTickTimer			= @"tick timer";
NSString*	CmdTimeline				= @"timeline";
NSString*	CmdReplies				= @"replies";
NSString*	CmdDM					= @"dm";
NSString*	CmdChannel				= @"channel";
NSString*	CmdStream				= @"stream";
NSString*	CmdStreamFinish			= @"stream_finish";
NSString*	CmdStreamError			= @"stream_error";

- (AfficheurService *)init
{
	self = [super init];
	if (self)
	{
		_mainThread = nil;
		_queueRetrieve = [[NSMutableArray alloc] init];
		_lockedRetrieve = NO;
		_lockRetrieve = [[NSLock alloc] init];
		_services = nil;
	}
	return self;
}


- (void)dealloc
{
	[_serviceTwitter release];
	[_serviceJaiku release];
	[_serviceTumblr release];
	[_serviceWassr release];
//	[_serviceNowa release];
	[_serviceIdentica  release];
//	[_serviceJisko release];
//	[_serviceChuitter release];
	[_serviceFriendFeed release];
	[_serviceFaceBook release];
	[_xmpp release];
	[_queueRetrieve release];
	[_lockRetrieve release];
	if (_services)
	{
		[_services release];
	}
	[super dealloc];
}

- (void)setupWithController:(AfficheurController *)controller
				preferences:(AfficheurPreferences *)preferences
{
	NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];
	_controller = controller;
	_preferences = preferences;
	_serviceTwitter    = [[ServiceTwitter    alloc] init:Twitter    WithController:_controller preferences:_preferences];
	_serviceJaiku      = [[ServiceJaiku      alloc] init:Jaiku      WithController:_controller preferences:_preferences];
	_serviceTumblr     = [[ServiceTumblr     alloc] init:Tumblr     WithController:_controller preferences:_preferences];
	_serviceWassr      = [[ServiceWassr      alloc] init:Wassr      WithController:_controller preferences:_preferences];
//	_serviceNowa       = [[ServiceNowa       alloc] init:Nowa       WithController:_controller preferences:_preferences];
	_serviceIdentica   = [[ServiceIdentica   alloc] init:Identica   WithController:_controller preferences:_preferences];
//	_serviceJisko      = [[ServiceJisko      alloc] init:Jisko      WithController:_controller preferences:_preferences];
//	_serviceChuitter   = [[ServiceChuitter   alloc] init:Chuitter   WithController:_controller preferences:_preferences];
	_serviceFriendFeed = [[ServiceFriendFeed alloc] init:FriendFeed WithController:_controller preferences:_preferences];
	_serviceFaceBook   = [[ServiceFaceBook   alloc] init:FaceBook   WithController:_controller preferences:_preferences];

	_services = [[NSDictionary dictionaryWithObjectsAndKeys:
				  _serviceTwitter,		Twitter,
				  _serviceJaiku,		Jaiku,
				  _serviceTumblr,		Tumblr,
				  _serviceWassr,		Wassr,
//				  _serviceNowa,			Nowa,
				  _serviceIdentica,		Identica,
//				  _serviceJisko,		Jisko,
//				  _serviceChuitter,		Chuitter,
				  _serviceFriendFeed,	FriendFeed,
				  _serviceFaceBook,	FaceBook,
				  nil] retain];
	[_serviceTwitter setupRetrieveDate:date];
	[_serviceJaiku setupRetrieveDate:date];
	[_serviceTumblr setupRetrieveDate:date];
//	[_serviceNowa setupRetrieveDate:date];
	[_serviceWassr setupRetrieveDate:date];
	[_serviceIdentica setupRetrieveDate:date];
//	[_serviceJisko setupRetrieveDate:date];
//	[_serviceChuitter setupRetrieveDate:date];
	[_serviceFriendFeed setupRetrieveDate:date];
	[_serviceFaceBook setupRetrieveDate:date];
	
	_xmpp = [[ServiceXMPP alloc] init];
	[_xmpp setController:controller];
	[self setupXMPP];
	
	[self performSelectorOnMainThread:@selector(getMainThread:)
						   withObject:nil
						waitUntilDone:YES];
	
	[self lockRetrieve];
	[NSThread detachNewThreadSelector:@selector(threadRetrieve:)
							 toTarget:self
						   withObject:nil];
	
	LOG(@"[%@ setupWithController] done", [self className]);
}

- (void)setupXMPP
{
	[_serviceJaiku setupXMPP:_xmpp];
	[_serviceWassr setupXMPP:_xmpp];
	[_serviceIdentica setupXMPP:_xmpp];
//	[_serviceJisko setupXMPP:_xmpp];
//	[_serviceChuitter setupXMPP:_xmpp];
}

- (void)getMainThread:(id)object
{
	_mainThread = [NSThread currentThread];
}

- (void)applicationWillTerminate;
{
	[_xmpp disconnectAll];
}

- (Service *)service:(NSString *)service
{
	return [_services valueForKey:service];
}

- (void)saveState:(BOOL)state
	   andEnabled:(BOOL)enabled
		  service:(NSString *)service
{
	if ([service isEqualToString:Twitter])
	{
		[_serviceTwitter saveState:state andEnabled:enabled];
	}
	else if ([service isEqualToString:Jaiku])
	{
		[_serviceJaiku saveState:state andEnabled:enabled];
	}
	else if ([service isEqualToString:Tumblr])
	{
		[_serviceTumblr saveState:state andEnabled:enabled];
	}
//	else if ([service isEqualToString:Nowa])
//	{
//		[_serviceNowa saveState:state andEnabled:enabled];
//	}
	else if ([service isEqualToString:Wassr])
	{
		[_serviceWassr saveState:state andEnabled:enabled];
	}
	else if ([service isEqualToString:Identica])
	{
		[_serviceIdentica saveState:state andEnabled:enabled];
	}
//	else if ([service isEqualToString:Jisko])
//	{
//		[_serviceJisko saveState:state andEnabled:enabled];
//	}
//	else if ([service isEqualToString:Chuitter])
//	{
//		[_serviceChuitter saveState:state andEnabled:enabled];
//	}
	else if ([service isEqualToString:FriendFeed])
	{
		[_serviceFriendFeed saveState:state andEnabled:enabled];
	}
	else if ([service isEqualToString:FaceBook])
	{
		[_serviceFaceBook saveState:state andEnabled:enabled];
	}
}

- (BOOL)status:(NSString *)service
{
	if ([service isEqualToString:Twitter])
	{
		return [_serviceTwitter status];
	}
	else if ([service isEqualToString:Jaiku])
	{
		return [_serviceJaiku status];
	}
	else if ([service isEqualToString:Tumblr])
	{
		return [_serviceTumblr status];
	}
//	else if ([service isEqualToString:Nowa])
//	{
//		return [_serviceNowa status];
//	}
	else if ([service isEqualToString:Wassr])
	{
		return [_serviceWassr status];
	}
	else if ([service isEqualToString:Identica])
	{
		return [_serviceIdentica status];
	}
//	else if ([service isEqualToString:Jisko])
//	{
//		return [_serviceJisko status];
//	}
//	else if ([service isEqualToString:Chuitter])
//	{
//		return [_serviceChuitter status];
//	}
	else if ([service isEqualToString:FriendFeed])
	{
		return [_serviceFriendFeed status];
	}
	else if ([service isEqualToString:FaceBook])
	{
		return [_serviceFaceBook status];
	}
	return NO;
}

- (BOOL)enable:(NSString *)service
{
	if ([service isEqualToString:Twitter])
	{
		return [_serviceTwitter enable];
	}
	else if ([service isEqualToString:Jaiku])
	{
		return [_serviceJaiku enable];
	}
	else if ([service isEqualToString:Tumblr])
	{
		return [_serviceTumblr enable];
	}
//	else if ([service isEqualToString:Nowa])
//	{
//		return [_serviceNowa enable];
//	}
	else if ([service isEqualToString:Wassr])
	{
		return [_serviceWassr enable];
	}
	else if ([service isEqualToString:Identica])
	{
		return [_serviceIdentica enable];
	}
//	else if ([service isEqualToString:Jisko])
//	{
//		return [_serviceJisko enable];
//	}
//	else if ([service isEqualToString:Chuitter])
//	{
//		return [_serviceChuitter enable];
//	}
	else if ([service isEqualToString:FriendFeed])
	{
		return [_serviceFriendFeed enable];
	}
	else if ([service isEqualToString:FaceBook])
	{
		return [_serviceFaceBook enable];
	}
	return NO;
}

- (int)rateLimitOfTwitter
{
	return [_serviceTwitter rateLimit];
}

- (void)performPost:(id)objects
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	LOG(@"[%@ performPost]", [self className]);
	@try
	{
		[_controller lockPost];
		NSString *status = [objects objectAtIndex:0];
		NSString *inReplyTo = [objects objectAtIndex:1];
		NSString *inReplyToService = [objects objectAtIndex:2];
		BOOL altEncodeTinyURL = [[objects objectAtIndex:3] boolValue];
		if (inReplyTo && ([inReplyTo isKindOfClass:[NSNull class]] || [inReplyTo isEqualToString:@""]))
		{
			inReplyTo = nil;
		}
		if (inReplyToService && ([inReplyToService isKindOfClass:[NSNull class]] || [inReplyToService isEqualToString:@""]))
		{
			inReplyToService = nil;
		}
		int postCount = 0;
		NSMutableArray *postQueue = [NSMutableArray array];
		NSString *encode = [NSString stringWithString:status];
		BOOL encodeTinyURL = [_preferences generalEncodeTinyURL];
		if (altEncodeTinyURL)
		{
			encodeTinyURL = !encodeTinyURL;
		}
		if (encodeTinyURL)
		{
			encode = [_controller encodeTinyURL:encode];
		}
		if (!encode)
		{
			postCount = -1;
		}
		else if (![status isEqualTo:@""])
		{
			@try
			{
				if ([_controller isEnabled:Twitter] && [_preferences postTwitter])
				{
					postCount++;
					[postQueue addObject:Twitter];
				}
				if ([_controller isEnabled:Jaiku] && [_preferences postJaiku])
				{
					postCount++;
					[postQueue addObject:Jaiku];
				}
				if ([_controller isEnabled:Tumblr] && [_preferences postTumblr] && [_controller isURL:encode])
				{
					postCount++;
					[postQueue addObject:Tumblr];
				}
				if ([_controller isEnabled:Wassr] && [_preferences postWassr])
				{
					postCount++;
					[postQueue addObject:Wassr];
				}
				if ([_controller isEnabled:Identica] && [_preferences postIdentica])
				{
					postCount++;
					[postQueue addObject:Identica];
				}
//				if ([_controller isEnabled:Jisko] && [_preferences postJisko])
//				{
//					postCount++;
//					[postQueue addObject:Jisko];
//				}
//				if ([_controller isEnabled:Chuitter] && [_preferences postChuitter])
//				{
//					postCount++;
//					[postQueue addObject:Chuitter];
//				}
				if ([_controller isEnabled:FriendFeed] && [_preferences postFriendFeed])
				{
					postCount++;
					[postQueue addObject:FriendFeed];
				}
				if ([_controller isEnabled:FaceBook] && [_preferences postFaceBook])
				{
					postCount++;
					[postQueue addObject:FaceBook];
				}
			}
			@catch (NSException *exception)
			{
				EXPLOG(@"[%@ performPost] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
			}
		}
		[_controller posted:postCount];
		[_controller unlockPost];
		while ([postQueue count] > 0)
		{
			@try
			{
				NSString *service = [postQueue objectAtIndex:0];
				if ([service isEqualToString:Twitter])
				{
					NSString *reply = @"";
					if (inReplyTo && [inReplyToService isEqualToString:Twitter])
					{
						reply = inReplyTo;
					}
					[_serviceTwitter post:encode
								withReply:reply];
				}
				if ([service isEqualToString:Jaiku])
				{
					if ([_preferences accountJaikuUseXMPP] && [_preferences accountJaikuPostXMPP])
					{
						[_xmpp post:encode withService:Jaiku];
					}
					else if (inReplyTo && ![inReplyTo isEqualToString:@""]
							 && [inReplyToService isEqualToString:Jaiku])
					{
						[_serviceJaiku comment:encode
									  withItem:inReplyTo];
					}
					else
					{
						[_serviceJaiku post:encode withIcon:[_controller iconCode]];
					}
				}
				if ([service isEqualToString:Tumblr])
				{
					[_serviceTumblr post:encode];
				}
				if ([service isEqualToString:Wassr])
				{
					NSString *reply = @"";
					if (inReplyTo && [inReplyToService isEqualToString:Wassr])
					{
						reply = inReplyTo;
					}
					[_serviceWassr post:encode
							  withReply:reply];
				}
				if ([service isEqualToString:Identica])
				{
					NSString *reply = @"";
					if (inReplyTo && [inReplyToService isEqualToString:Identica])
					{
						reply = inReplyTo;
					}
					if ([_preferences accountIdenticaUseXMPP] && [_preferences accountIdenticaPostXMPP])
					{
						[_xmpp post:encode withService:Identica];
					}
					else
					{
						[_serviceIdentica post:encode
									 withReply:reply];
					}
				}
//				if ([service isEqualToString:Jisko])
//				{
//					NSString *reply = @"";
//					if (inReplyTo && [inReplyToService isEqualToString:Jisko])
//					{
//						reply = inReplyTo;
//					}
//					[_serviceJisko post:encode
//							  withReply:reply];
//				}
//				if ([service isEqualToString:Chuitter])
//				{
//					NSString *reply = @"";
//					if (inReplyTo && [inReplyToService isEqualToString:Chuitter])
//					{
//						reply = inReplyTo;
//					}
//					[_serviceChuitter post:encode
//								 withReply:reply];
//				}
				if ([service isEqualToString:FriendFeed])
				{
					NSString *reply = @"";
					if (inReplyTo && [inReplyToService isEqualToString:FriendFeed])
					{
						reply = inReplyTo;
					}
					[_serviceFriendFeed post:encode
								   withReply:reply];
				}
				if ([service isEqualToString:FaceBook])
				{
					NSString *reply = @"";
					if (inReplyTo && [inReplyToService isEqualToString:FaceBook])
					{
						reply = inReplyTo;
					}
					[_serviceFaceBook post:encode
								 withReply:reply];
				}
			}
			@catch (NSException *exception)
			{
				EXPLOG(@"[%@ performPost] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
			}
			@finally
			{
				[postQueue removeObjectAtIndex:0];
			}
		}
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performPost] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
	LOG(@"[%@ performPost] done", [self className]);
	[pool release];
	[NSThread exit];
}

- (void)post:(NSString *)status
withInReplyTo:(NSString *)inReplyTo
inReplyToService:(NSString *)inReplyToService
altEncodeTinyURL:(BOOL)altEncodeTinyURL
{
	LOG(@"[%@ post]", [self className]);
	//LOG(@"[%@ post] status: %p\n'%@'", [self className], status, status);
	//LOG(@"[%@ post] inReplyTo: %p\n'%@'", [self className], inReplyTo, inReplyTo);
	//LOG(@"[%@ post] inReplyToService: %p", [self className], inReplyToService);
	//LOG(@"[%@ post] inReplyToService: %p\n'%@'", [self className], inReplyToService, inReplyToService);
	//LOG(@"[%@ post] altEncodeTinyURL: %d", [self className], altEncodeTinyURL);
	@try
	{
		NSArray *objects = [[NSArray alloc] initWithObjects:
							status,
							(inReplyTo ? inReplyTo : (id)[NSNull null]),
							(inReplyToService ? inReplyToService : (id)[NSNull null]),
							[NSNumber numberWithBool:altEncodeTinyURL],
							nil];
		LOG(@"[%@ post]\n%@", [self className], objects);
		[NSThread detachNewThreadSelector:@selector(performPost:)
								 toTarget:self
							   withObject:objects];
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ post] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

- (void)doRetrieveTimelineTwitter
{
	if ([_controller isEnabled:Twitter])
	{
		[_serviceTwitter retrieveTimeline];
	}
}

- (void)doRetrieveTimelineJaiku
{
	if ([_controller isEnabled:Jaiku])
	{
		[_serviceJaiku retrieveContactsFeed];
	}
}

- (void)doRetrieveTimelineTumblr
{
	if ([_controller isEnabled:Tumblr])
	{
		[_serviceTumblr retrieveTimeline];
	}
}

- (void)doRetrieveTimelineWassr
{
	if ([_controller isEnabled:Wassr])
	{
		[_serviceWassr retrieveTimeline];
	}
}

//- (void)doRetrieveTimelineNowa
//{
//	if ([_controller isEnabled:Nowa])
//	{
//		[_serviceNowa retrieveTimeline];
//	}
//}

- (void)doRetrieveTimelineIdentica
{
	if ([_controller isEnabled:Identica])
	{
		[_serviceIdentica retrieveTimeline];
	}
}

//- (void)doRetrieveTimelineJisko
//{
//	if ([_controller isEnabled:Jisko])
//	{
//		[_serviceJisko retrieveTimeline];
//	}
//}

//- (void)doRetrieveTimelineChuitter
//{
//	if ([_controller isEnabled:Chuitter])
//	{
//		[_serviceChuitter retrieveTimeline];
//	}
//}

- (void)doRetrieveTimelineFriendFeed
{
	if ([_controller isEnabled:FriendFeed])
	{
		[_serviceFriendFeed retrieveHomeFeed];
	}
}

- (void)doRetrieveTimelineFaceBook
{
	if ([_controller isEnabled:FaceBook])
	{
		[_serviceFaceBook retrieveHomeFeed];
	}
}

- (void)doRetrieveRepliesTwitter
{
	if ([_controller isEnabled:Twitter])
	{
		[_serviceTwitter retrieveReplies];
	}
}

- (void)doRetrieveRepliesWassr
{
	if ([_controller isEnabled:Wassr])
	{
		[_serviceWassr retrieveReplies];
	}
}

- (void)doRetrieveRepliesIdentica
{
	if ([_controller isEnabled:Identica])
	{
		[_serviceIdentica retrieveReplies];
	}
}

//- (void)doRetrieveRepliesJisko
//{
//	if ([_controller isEnabled:Jisko])
//	{
//		[_serviceJisko retrieveReplies];
//	}
//}

//- (void)doRetrieveRepliesChuitter
//{
//	if ([_controller isEnabled:Chuitter])
//	{
//		[_serviceChuitter retrieveReplies];
//	}
//}

- (void)doRetrieveDirectMessageTwitter
{
	if ([_controller isEnabled:Twitter])
	{
		[_serviceTwitter retrieveDirectMessage];
	}
}

- (void)doRetrieveDirectMessageIdentica
{
	if ([_controller isEnabled:Identica])
	{
		[_serviceIdentica retrieveDirectMessage];
	}
}

//- (void)doRetrieveDirectMessageJisko
//{
//	if ([_controller isEnabled:Jisko])
//	{
//		[_serviceJisko retrieveDirectMessage];
//	}
//}

//- (void)doRetrieveDirectMessageChuitter
//{
//	if ([_controller isEnabled:Chuitter])
//	{
//		[_serviceChuitter retrieveDirectMessage];
//	}
//}

- (void)doRetrieveChannelWassr
{
	if ([_controller isEnabled:Wassr])
	{
		[_serviceWassr retrieveChannel];
	}
}

- (void)doFavoriteTwitter:(NSString *)item_id
{
	if ([_controller isEnabled:Twitter])
	{
		[_serviceTwitter favorite:item_id];
	}
}

- (void)doFavoriteTumblr:(NSString *)item_id
{
	if ([_controller isEnabled:Tumblr])
	{
		[_serviceTumblr favorite:item_id];
	}
}

- (void)doFavoriteWassr:(NSString *)item_id
{
	if ([_controller isEnabled:Wassr])
	{
		id item = [_controller fetchTimeline:item_id withService:Wassr];
		if (item)
		{
			NSString *rid = [item valueForKey:KeyRId];
			[_serviceWassr favorite:rid];
		}
	}
}

- (void)doFavoriteIdentica:(NSString *)item_id
{
	if ([_controller isEnabled:Identica])
	{
		[_serviceIdentica favorite:item_id];
	}
}

//- (void)doFavoriteJisko:(NSString *)item_id
//{
//	if ([_controller isEnabled:Jisko])
//	{
//		[_serviceJisko favorite:item_id];
//	}
//}

//- (void)doFavoriteChuitter:(NSString *)item_id
//{
//	if ([_controller isEnabled:Chuitter])
//	{
//		[_serviceChuitter favorite:item_id];
//	}
//}

- (void)doFavoriteFriendFeed:(NSString *)item_id
{
	if ([_controller isEnabled:FriendFeed])
	{
		[_serviceFriendFeed favorite:item_id];
	}
}

- (void)doFavoriteFaceBook:(NSString *)item_id
{
	if ([_controller isEnabled:FaceBook])
	{
		[_serviceFaceBook favorite:item_id];
	}
}

- (void)doFavorite:(NSString *)item_id
	   withService:(NSString *)service
{
	//LOG(@"[%@ doFavorite] %@ : %@", [self className], item_id, service);
	if ([service isEqualToString:Twitter])
	{
		[self doFavoriteTwitter:item_id];
	}
	else if ([service isEqualToString:Tumblr])
	{
		[self doFavoriteTumblr:item_id];
	}
	else if ([service isEqualToString:Wassr])
	{
		[self doFavoriteWassr:item_id];
	}
	else if ([service isEqualToString:Identica])
	{
		[self doFavoriteIdentica:item_id];
	}
//	else if ([service isEqualToString:Jisko])
//	{
//		[self doFavoriteJisko:item_id];
//	}
//	else if ([service isEqualToString:Chuitter])
//	{
//		[self doFavoriteChuitter:item_id];
//	}
	else if ([service isEqualToString:FriendFeed])
	{
		[self doFavoriteFriendFeed:item_id];
	}
	else if ([service isEqualToString:FaceBook])
	{
		[self doFavoriteFaceBook:item_id];
	}
}

- (void)doPermalinkTwitter:(NSString *)item_id
{
	if ([_controller isEnabled:Twitter])
	{
		[_serviceTwitter permalink:item_id];
	}
}

- (void)doPermalinkJaiku:(NSString *)item_id
{
	if ([_controller isEnabled:Jaiku])
	{
		[_serviceJaiku permalink:item_id];
	}
}

- (void)doPermalinkWassr:(NSString *)item_id
{
	if ([_controller isEnabled:Wassr])
	{
		[_serviceWassr permalink:item_id];
	}
}

//- (void)doPermalinkNowa:(NSString *)item_id
//{
//	if ([_controller isEnabled:Nowa])
//	{
//		[_serviceNowa permalink:item_id];
//	}
//}

- (void)doPermalinkIdentica:(NSString *)item_id
{
	if ([_controller isEnabled:Identica])
	{
		[_serviceIdentica permalink:item_id];
	}
}

//- (void)doPermalinkJisko:(NSString *)item_id
//{
//	if ([_controller isEnabled:Jisko])
//	{
//		[_serviceJisko permalink:item_id];
//	}
//}

//- (void)doPermalinkChuitter:(NSString *)item_id
//{
//	if ([_controller isEnabled:Chuitter])
//	{
//		[_serviceChuitter permalink:item_id];
//	}
//}

- (void)doPermalinkFriendFeed:(NSString *)item_id
{
	if ([_controller isEnabled:FriendFeed])
	{
		[_serviceFriendFeed permalink:item_id];
	}
}

- (void)doPermalinkFaceBook:(NSString *)item_id
{
	if ([_controller isEnabled:FaceBook])
	{
		[_serviceFaceBook permalink:item_id];
	}
}

- (void)doPermalink:(NSString *)item_id
		withService:(NSString *)service
{
	//LOG(@"[%@ doPermalink] %@ : %@", [self className], item_id, service);
	if ([service isEqualToString:Twitter])
	{
		[self doPermalinkTwitter:item_id];
	}
	else if ([service isEqualToString:Jaiku])
	{
		[self doPermalinkJaiku:item_id];
	}
	else if ([service isEqualToString:Wassr])
	{
		[self doPermalinkWassr:item_id];
	}
//	else if ([service isEqualToString:Nowa])
//	{
//		[self doPermalinkNowa:item_id];
//	}
	else if ([service isEqualToString:Identica])
	{
		[self doPermalinkIdentica:item_id];
	}
//	else if ([service isEqualToString:Jisko])
//	{
//		[self doPermalinkJisko:item_id];
//	}
//	else if ([service isEqualToString:Chuitter])
//	{
//		[self doPermalinkChuitter:item_id];
//	}
	else if ([service isEqualToString:FriendFeed])
	{
		[self doPermalinkFriendFeed:item_id];
	}
	else if ([service isEqualToString:FaceBook])
	{
		[self doPermalinkFaceBook:item_id];
	}
}

- (void)doOpenURLTwitter:(NSString *)item_id
{
	if ([_controller isEnabled:Twitter])
	{
		[_serviceTwitter openURL:item_id];
	}
}

- (void)doOpenURLJaiku:(NSString *)item_id
{
	if ([_controller isEnabled:Jaiku])
	{
		[_serviceJaiku openURL:item_id];
	}
}

- (void)doOpenURLTumblr:(NSString *)item_id
{
	if ([_controller isEnabled:Tumblr])
	{
		[_serviceTumblr openURL:item_id];
	}
}

- (void)doOpenURLWassr:(NSString *)item_id
{
	if ([_controller isEnabled:Wassr])
	{
		[_serviceWassr openURL:item_id];
	}
}

//- (void)doOpenURLNowa:(NSString *)item_id
//{
//	if ([_controller isEnabled:Nowa])
//	{
//		[_serviceNowa openURL:item_id];
//	}
//}

- (void)doOpenURLIdentica:(NSString *)item_id
{
	if ([_controller isEnabled:Identica])
	{
		[_serviceIdentica openURL:item_id];
	}
}

//- (void)doOpenURLJisko:(NSString *)item_id
//{
//	if ([_controller isEnabled:Jisko])
//	{
//		[_serviceJisko openURL:item_id];
//	}
//}

//- (void)doOpenURLChuitter:(NSString *)item_id
//{
//	if ([_controller isEnabled:Chuitter])
//	{
//		[_serviceChuitter openURL:item_id];
//	}
//}

- (void)doOpenURLFriendFeed:(NSString *)item_id
{
	if ([_controller isEnabled:FriendFeed])
	{
		[_serviceFriendFeed openURL:item_id];
	}
}

- (void)doOpenURLFaceBook:(NSString *)item_id
{
	if ([_controller isEnabled:FaceBook])
	{
		[_serviceFaceBook openURL:item_id];
	}
}

- (void)doOpenURL:(NSString *)item_id
	  withService:(NSString *)service
{
	//LOG(@"[%@ doOpenURL] %@ : %@", [self className], item_id, service);
	if ([service isEqualToString:Twitter])
	{
		[self doOpenURLTwitter:item_id];
	}
	else if ([service isEqualToString:Jaiku])
	{
		[self doOpenURLJaiku:item_id];
	}
	else if ([service isEqualToString:Tumblr])
	{
		[self doOpenURLTumblr:item_id];
	}
	else if ([service isEqualToString:Wassr])
	{
		[self doOpenURLWassr:item_id];
	}
//	else if ([service isEqualToString:Nowa])
//	{
//		[self doOpenURLNowa:item_id];
//	}
	else if ([service isEqualToString:Identica])
	{
		[self doOpenURLIdentica:item_id];
	}
//	else if ([service isEqualToString:Jisko])
//	{
//		[self doOpenURLJisko:item_id];
//	}
//	else if ([service isEqualToString:Chuitter])
//	{
//		[self doOpenURLChuitter:item_id];
//	}
	else if ([service isEqualToString:FriendFeed])
	{
		[self doOpenURLFriendFeed:item_id];
	}
	else if ([service isEqualToString:FaceBook])
	{
		[self doOpenURLFaceBook:item_id];
	}
}

- (void)doReplyTwitter:(NSString *)item_id
{
	if ([_controller isEnabled:Twitter])
	{
		[_serviceTwitter doReply:item_id];
	}
}

- (void)doReplyJaiku:(NSString *)item_id
{
	if ([_controller isEnabled:Jaiku])
	{
		[_serviceJaiku doReply:item_id];
	}
}

//- (void)doReplyNowa:(NSString *)item_id
//{
//	if ([_controller isEnabled:Nowa])
//	{
//		[_serviceNowa doReply:item_id];
//	}
//}

- (void)doReplyWassr:(NSString *)item_id
{
	if ([_controller isEnabled:Wassr])
	{
		[_serviceWassr doReply:item_id];
	}
}

- (void)doReplyIdentica:(NSString *)item_id
{
	if ([_controller isEnabled:Identica])
	{
		[_serviceIdentica doReply:item_id];
	}
}

//- (void)doReplyJisko:(NSString *)item_id
//{
//	if ([_controller isEnabled:Jisko])
//	{
//		[_serviceJisko doReply:item_id];
//	}
//}

//- (void)doReplyChuitter:(NSString *)item_id
//{
//	if ([_controller isEnabled:Chuitter])
//	{
//		[_serviceChuitter doReply:item_id];
//	}
//}

- (void)doReplyFriendFeed:(NSString *)item_id
{
	if ([_controller isEnabled:FriendFeed])
	{
		[_serviceFriendFeed doReply:item_id];
	}
}

- (void)doReplyFaceBook:(NSString *)item_id
{
	if ([_controller isEnabled:FaceBook])
	{
		[_serviceFaceBook doReply:item_id];
	}
}

- (void)doReply:(NSString *)item_id
	withService:(NSString *)service
{
	//LOG(@"[%@ doReply]\n%@, %@", [self className], item_id, service);
	if ([service isEqualToString:Twitter])
	{
		[self doReplyTwitter:item_id];
	}
	else if ([service isEqualToString:Jaiku])
	{
		[self doReplyJaiku:item_id];
	}
//	else if ([service isEqualToString:Nowa])
//	{
//		[self doReplyNowa:item_id];
//	}
	else if ([service isEqualToString:Wassr])
	{
		[self doReplyWassr:item_id];
	}
	else if ([service isEqualToString:Identica])
	{
		[self doReplyIdentica:item_id];
	}
//	else if ([service isEqualToString:Jisko])
//	{
//		[self doReplyJisko:item_id];
//	}
//	else if ([service isEqualToString:Chuitter])
//	{
//		[self doReplyChuitter:item_id];
//	}
	else if ([service isEqualToString:FriendFeed])
	{
		[self doReplyFriendFeed:item_id];
	}
	else if ([service isEqualToString:FaceBook])
	{
		[self doReplyFaceBook:item_id];
	}
}

- (void)doRetweetViaAPI:(NSString *)item_id
			withService:(NSString *)service;
{
	[[self service:service] doRetweetViaAPI:item_id];
}

- (void)doDirectMessage:(NSString *)item_id
			withService:(NSString *)service
{
	[[self service:service] doDirectMessage:item_id];
}

- (void)doCopyPermalink:(NSString *)item_id
			withService:(NSString *)service
{
	//LOG(@"[%@ doCopyPermalink] %@ : %@", [self className], item_id, service);
	NSString *url = nil;
	if ([service isEqualToString:Twitter])
	{
		url = [_serviceTwitter permalinkURL:item_id];
	}
	else if ([service isEqualToString:Jaiku])
	{
		url = [_serviceJaiku permalinkURL:item_id];
	}
	else if ([service isEqualToString:Tumblr])
	{
	}
	else if ([service isEqualToString:Wassr])
	{
		url = [_serviceWassr permalinkURL:item_id];
	}
	//	else if ([service isEqualToString:Nowa])
	//	{
	//		[self doOpenURLNowa:item_id];
	//	}
	else if ([service isEqualToString:Identica])
	{
		url = [_serviceIdentica permalinkURL:item_id];
	}
	//	else if ([service isEqualToString:Jisko])
	//	{
	//		[self doOpenURLJisko:item_id];
	//	}
	//	else if ([service isEqualToString:Chuitter])
	//	{
	//		[self doOpenURLChuitter:item_id];
	//	}
	else if ([service isEqualToString:FriendFeed])
	{
		url = [_serviceFriendFeed permalinkURL:item_id];
	}
	else if ([service isEqualToString:FaceBook])
	{
		url = [_serviceFaceBook permalinkURL:item_id];
	}
	if (url)
	{
		LOG2(@"[%@ doCopyPermalink]\n%@", [self className], url);
		NSPasteboard* pb = [NSPasteboard generalPasteboard];
		[pb declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:self];
		[pb setString:url forType:NSStringPboardType];
	}
}

- (void)performLockRetrieve:(id)object
{
	@synchronized(_lockRetrieve)
	{
		_lockedRetrieve = YES;
		[_lockRetrieve lock];
	}
}

- (void)lockRetrieve
{
	if ([[NSThread currentThread] isEqual:_mainThread])
	{
		[self performLockRetrieve:nil];
	}
	else
	{
		[self performSelectorOnMainThread:@selector(performLockRetrieve:)
							   withObject:nil
							waitUntilDone:YES];
	}
}

- (void)performUnlockRetrieve:(id)object
{
	@synchronized(_lockRetrieve)
	{
		if (_lockedRetrieve)
		{
			_lockedRetrieve = NO;
			[_lockRetrieve unlock];
		}
	}
}

- (void)unlockRetrieve
{
	if ([[NSThread currentThread] isEqual:_mainThread])
	{
		[self performUnlockRetrieve:nil];
	}
	else
	{
		[self performSelectorOnMainThread:@selector(performUnlockRetrieve:)
							   withObject:nil
							waitUntilDone:YES];
	}
}

- (void)queueingCommand:(NSString *)command
			withService:(NSString *)service
				 object:(id)object
{
	@synchronized(_queueRetrieve)
	{
		NSEnumerator *enumerator = [_queueRetrieve objectEnumerator];
		id obj;
		BOOL queueing = YES;
		if (![command isEqualToString:CmdStream])
		{
			while ((obj = [enumerator nextObject]))
			{
				if ([[obj valueForKey:KeyTimelineCommand] isEqualToString:command] &&
					[[obj valueForKey:KeyTimelineService] isEqualToString:service])
				{
					queueing = NO;
					break;
				}
			}
		}
		if (queueing)
		{
			//LOG(@"[%@ queueingCommand] %@:%@", [self className], service, command);
			[_queueRetrieve addObject:[NSDictionary dictionaryWithObjectsAndKeys:
									   command, KeyTimelineCommand,
									   service, KeyTimelineService,
									   object, KeyTimelineObject,
									   nil]];
		}
	}
	//[self unlockRetrieve];
}

- (void)queueingCommand:(NSString *)command
			withService:(NSString *)service
{
	[self queueingCommand:command
			  withService:service
				   object:nil];
}

- (void)doRetrieveTimeline
{
	BOOL queueing = NO;
	if ([_preferences accountTwitterExecMenu])
	{
		[self queueingCommand:CmdTimeline withService:Twitter];
		queueing = YES;
	}
	if ([_preferences accountTumblrExecMenu])
	{
		[self queueingCommand:CmdTimeline withService:Tumblr];
		queueing = YES;
	}
	if ([_preferences accountWassrExecMenu])
	{
		[self queueingCommand:CmdTimeline withService:Wassr];
		[self queueingCommand:CmdChannel withService:Wassr];
		queueing = YES;
	}
//	if ([_preferences accountNowaExecMenu])
//	{
//		[self queueingCommand:CmdTimeline withService:Nowa];
//		queueing = YES;
//	}
	if ([_preferences accountIdenticaExecMenu])
	{
		[self queueingCommand:CmdTimeline withService:Identica];
		queueing = YES;
	}
//	if ([_preferences accountJiskoExecMenu])
//	{
//		[self queueingCommand:CmdTimeline withService:Jisko];
//		queueing = YES;
//	}
	if ([_preferences accountJaikuExecMenu])
	{
		[self queueingCommand:CmdTimeline withService:Jaiku];
		queueing = YES;
	}
//	if ([_preferences accountChuitterExecMenu])
//	{
//		[self queueingCommand:CmdTimeline withService:Chuitter];
//		queueing = YES;
//	}
	if ([_preferences accountFriendFeedExecMenu])
	{
		[self queueingCommand:CmdTimeline withService:FriendFeed];
		queueing = YES;
	}
	if ([_preferences accountFaceBookExecMenu])
	{
		[self queueingCommand:CmdTimeline withService:FaceBook];
		queueing = YES;
	}
	if (queueing)
	{
		[self unlockRetrieve];
	}
}

- (void)doRetrieveReplies
{
	BOOL queueing = NO;
	if ([_preferences accountTwitterExecMenu])
	{
		[self queueingCommand:CmdReplies withService:Twitter];
		queueing = YES;
	}
	if ([_preferences accountWassrExecMenu])
	{
		[self queueingCommand:CmdReplies withService:Wassr];
		queueing = YES;
	}
	if ([_preferences accountIdenticaExecMenu])
	{
		[self queueingCommand:CmdReplies withService:Identica];
		queueing = YES;
	}
//	if ([_preferences accountJiskoExecMenu])
//	{
//		[self queueingCommand:CmdReplies withService:Jisko];
//		queueing = YES;
//	}
//	if ([_preferences accountChuitterExecMenu])
//	{
//		[self queueingCommand:CmdReplies withService:Chuitter];
//		queueing = YES;
//	}
	if (queueing)
	{
		[self unlockRetrieve];
	}
}

- (void)doRetrieveDirectMessage
{
	BOOL queueing = NO;
	if ([_preferences accountTwitterExecMenu])
	{
		[self queueingCommand:CmdDM withService:Twitter];
		queueing = YES;
	}
	if ([_preferences accountIdenticaExecMenu])
	{
		[self queueingCommand:CmdDM withService:Identica];
		queueing = YES;
	}
//	if ([_preferences accountJiskoExecMenu])
//	{
//		[self queueingCommand:CmdDM withService:Jisko];
//		queueing = YES;
//	}
//	if ([_preferences accountChuitterExecMenu])
//	{
//		[self queueingCommand:CmdDM withService:Chuitter];
//		queueing = YES;
//	}
	if (queueing)
	{
		[self unlockRetrieve];
	}
}

- (void)doTickTimer
{
	//LOG(@"[%@ performTickTimer]", [self className]);
	NSDate *date =[NSDate dateWithTimeIntervalSinceNow:0];
	@try
	{
		if (![_controller isSleep])
		{
			BOOL queueing = NO;
			// Twitter
			if ([_preferences accountTwitterUseStream])
			{
				if (![_serviceTwitter isStream])
				{
					if ([_serviceTwitter userStream])
					{
						[_serviceTwitter setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
						[self queueingCommand:CmdTimeline withService:Twitter];
						[_serviceTwitter setupRetrieveDateReplies:[NSDate dateWithTimeIntervalSinceNow:36000]];
						[self queueingCommand:CmdReplies withService:Twitter];
						[_serviceTwitter setupRetrieveDateDM:[NSDate dateWithTimeIntervalSinceNow:36000]];
						[self queueingCommand:CmdDM withService:Twitter];
						queueing = YES;
					}
				}
			}
			else
			{
				[_serviceTwitter closeStream];
			}
			if ([_serviceTwitter checkRetrieveTimeline:date])
			{
				[_serviceTwitter setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdTimeline withService:Twitter];
				queueing = YES;
			}
			if ([_serviceTwitter checkRetrieveReplies:date])
			{
				[_serviceTwitter setupRetrieveDateReplies:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdReplies withService:Twitter];
				queueing = YES;
			}
			if ([_serviceTwitter checkRetrieveDM:date])
			{
				[_serviceTwitter setupRetrieveDateDM:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdDM withService:Twitter];
				queueing = YES;
			}
			// Tumblr
			if ([_serviceTumblr checkRetrieveTimeline:date])
			{
				[_serviceTumblr setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdTimeline withService:Tumblr];
				queueing = YES;
			}
			// Wassr
			if ([_serviceWassr checkRetrieveTimeline:date])
			{
				[_serviceWassr setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdTimeline withService:Wassr];
				queueing = YES;
			}
			if ([_serviceWassr checkRetrieveReplies:date])
			{
				[_serviceWassr setupRetrieveDateReplies:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdReplies withService:Wassr];
				queueing = YES;
			}
			if ([_serviceWassr checkRetrieveChannel:date])
			{
				[_serviceWassr setupRetrieveDateChannel:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdChannel withService:Wassr];
				queueing = YES;
			}
			//// nowa
			//if ([_serviceNowa checkRetrieveTimeline:date])
			//{
			//	[_serviceNowa setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
			//	[self queueingCommand:CmdTimeline withService:Nowa];
			//	queueing = YES;
			//}
			// Identica
			if ([_serviceIdentica checkRetrieveTimeline:date])
			{
				[_serviceIdentica setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdTimeline withService:Identica];
				queueing = YES;
			}
			if ([_serviceIdentica checkRetrieveReplies:date])
			{
				[_serviceIdentica setupRetrieveDateReplies:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdReplies withService:Identica];
				queueing = YES;
			}
			if ([_serviceIdentica checkRetrieveDM:date])
			{
				[_serviceIdentica setupRetrieveDateDM:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdDM withService:Identica];
				queueing = YES;
			}
//			// Jisko
//			if ([_serviceJisko checkRetrieveTimeline:date])
//			{
//				[_serviceJisko setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
//				[self queueingCommand:CmdTimeline withService:Jisko];
//				queueing = YES;
//			}
//			if ([_serviceJisko checkRetrieveReplies:date])
//			{
//				[_serviceJisko setupRetrieveDateReplies:[NSDate dateWithTimeIntervalSinceNow:36000]];
//				[self queueingCommand:CmdReplies withService:Jisko];
//				queueing = YES;
//			}
//			if ([_serviceJisko checkRetrieveDM:date])
//			{
//				[_serviceJisko setupRetrieveDateDM:[NSDate dateWithTimeIntervalSinceNow:36000]];
//				[self queueingCommand:CmdDM withService:Jisko];
//				queueing = YES;
//			}
//			// Chuitter
//			if ([_serviceChuitter checkRetrieveTimeline:date])
//			{
//				[_serviceChuitter setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
//				[self queueingCommand:CmdTimeline withService:Chuitter];
//				queueing = YES;
//			}
//			if ([_serviceChuitter checkRetrieveReplies:date])
//			{
//				[_serviceChuitter setupRetrieveDateReplies:[NSDate dateWithTimeIntervalSinceNow:36000]];
//				[self queueingCommand:CmdReplies withService:Chuitter];
//				queueing = YES;
//			}
//			if ([_serviceChuitter checkRetrieveDM:date])
//			{
//				[_serviceChuitter setupRetrieveDateDM:[NSDate dateWithTimeIntervalSinceNow:36000]];
//				[self queueingCommand:CmdDM withService:Chuitter];
//				queueing = YES;
//			}
			// Jaiku
			if ([_serviceJaiku checkRetrieveTimeline:date])
			{
				[_serviceJaiku setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdTimeline withService:Jaiku];
				queueing = YES;
			}
			// FriendFeed
			if ([_serviceFriendFeed checkRetrieveTimeline:date])
			{
				[_serviceFriendFeed setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdTimeline withService:FriendFeed];
				queueing = YES;
			}
			// FaceBook
			if ([_serviceFaceBook checkRetrieveTimeline:date])
			{
				[_serviceFaceBook setupRetrieveDateTimeline:[NSDate dateWithTimeIntervalSinceNow:36000]];
				[self queueingCommand:CmdTimeline withService:FaceBook];
				queueing = YES;
			}
			if (queueing)
			{
				[self unlockRetrieve];
			}
		}
		// XMPP
		[_xmpp keepConnections:date];
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ performTickTimer] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

- (void)threadRetrieve:(id)object
{
	//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	for (;;)
	{
		NSAutoreleasePool *internalPool = [[NSAutoreleasePool alloc] init];
		[_lockRetrieve lock];
		@try
		{
			id obj;
			int count = 0;
			NSMutableArray *twitterStream = [NSMutableArray array];
			@synchronized(_queueRetrieve)
			{
				count = [_queueRetrieve count];
			}
			while (count > 0)
			{
				@try
				{
					@synchronized(_queueRetrieve)
					{
						obj = [_queueRetrieve objectAtIndex:0];
					}
					NSString *command = [obj valueForKey:KeyTimelineCommand];
					NSString *service = [obj valueForKey:KeyTimelineService];
					LOG(@"[%@ threadRetrieve] %@:%@", [self className], service, command);
					if ([command isEqualToString:CmdTickTimer])
					{
						[self doTickTimer];
					}
					else if ([command isEqualToString:CmdTimeline])
					{
						if ([service isEqualToString:Twitter])
						{
							[self doRetrieveTimelineTwitter];
						}
						else if ([service isEqualToString:Jaiku])
						{
							[self doRetrieveTimelineJaiku];
						}
						else if ([service isEqualToString:Tumblr])
						{
							[self doRetrieveTimelineTumblr];
						}
						else if ([service isEqualToString:Wassr])
						{
							[self doRetrieveTimelineWassr];
						}
						//else if ([service isEqualToString:Nowa])
						//{
						//	[self doRetrieveTimelineNowa];
						//}
						else if ([service isEqualToString:Identica])
						{
							[self doRetrieveTimelineIdentica];
						}
						//else if ([service isEqualToString:Jisko])
						//{
						//	[self doRetrieveTimelineJisko];
						//}
						//else if ([service isEqualToString:Chuitter])
						//{
						//	[self doRetrieveTimelineChuitter];
						//}
						else if ([service isEqualToString:FriendFeed])
						{
							[self doRetrieveTimelineFriendFeed];
						}
						else if ([service isEqualToString:FaceBook])
						{
							[self doRetrieveTimelineFaceBook];
						}
					}
					else if ([command isEqualToString:CmdChannel])
					{
						if ([service isEqualToString:Wassr])
						{
							[self doRetrieveChannelWassr];
						}
					}
					else if ([command isEqualToString:CmdReplies])
					{
						if ([service isEqualToString:Twitter])
						{
							[self doRetrieveRepliesTwitter];
						}
						else if ([service isEqualToString:Wassr])
						{
							[self doRetrieveRepliesWassr];
						}
						else if ([service isEqualToString:Identica])
						{
							[self doRetrieveRepliesIdentica];
						}
						//else if ([service isEqualToString:Jisko])
						//{
						//	[self doRetrieveRepliesJisko];
						//}
						//else if ([service isEqualToString:Chuitter])
						//{
						//	[self doRetrieveRepliesChuitter];
						//}
					}
					else if ([command isEqualToString:CmdDM])
					{
						if ([service isEqualToString:Twitter])
						{
							[self doRetrieveDirectMessageTwitter];
						}
						else if ([service isEqualToString:Identica])
						{
							[self doRetrieveDirectMessageIdentica];
						}
						//else if ([service isEqualToString:Jisko])
						//{
						//	[self doRetrieveDirectMessageJisko];
						//}
						//else if ([service isEqualToString:Chuitter])
						//{
						//	[self doRetrieveDirectMessageChuitter];
						//}
					}
					else if ([command isEqualToString:CmdStream])
					{
						if ([service isEqualToString:Twitter])
						{
							[twitterStream addObject:[obj valueForKey:KeyTimelineObject]];
						}
					}
					else if ([command isEqualToString:CmdStreamFinish])
					{
						if ([service isEqualToString:Twitter])
						{
							[_serviceTwitter finishStream];
						}
					}
					else if ([command isEqualToString:CmdStreamError])
					{
						if ([service isEqualToString:Twitter])
						{
							NSError *object = [obj valueForKey:KeyTimelineObject];
							[_serviceTwitter errorStream:object];
							[object release];
						}
					}
					LOG(@"[%@ threadRetrieve] %@:%@ done", [self className], service, command);
				}
				@catch (NSException *exception)
				{
					EXPLOG(@"[%@ threadRetrieve] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
				}
				@finally
				{
					@synchronized(_queueRetrieve)
					{
						if ([_queueRetrieve count]> 0) {
							[_queueRetrieve removeObjectAtIndex:0];
						}
						count = [_queueRetrieve count];
					}
				}
			}
			if ([twitterStream count] > 0)
			{
				[_serviceTwitter receiveStream:twitterStream];
				while ([twitterStream count] > 0)
				{
					[[twitterStream objectAtIndex:0] release];
					[twitterStream removeObjectAtIndex:0];
				}
			}
		}
		@catch (NSException *exception)
		{
			EXPLOG(@"[%@ threadRetrieve] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
		}
		@finally
		{
			[_lockRetrieve unlock];
			[self lockRetrieve];
		}
		[internalPool release];
	}
//	[pool release];
	[NSThread exit];
}

- (void)tickTimer
{
	@try
	{
		[self queueingCommand:CmdTickTimer withService:@"@"];
		[self unlockRetrieve];
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ tickTimer] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

- (void)userStream:(id)userStream
	   withService:(NSString *)service
{
	@try
	{
		[self queueingCommand:CmdStream withService:service object:userStream];
		[self unlockRetrieve];
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ userStream] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

- (void)finishUserStreamWithService:(NSString *)service
{
	@try
	{
		[self queueingCommand:CmdStreamFinish withService:service object:@""];
		[self unlockRetrieve];
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ finishUserStream] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

- (void)errorUserStream:(NSError *)error
			withService:(NSString *)service
{
	@try
	{
		[self queueingCommand:CmdStreamError withService:service object:[error copy]];
		[self unlockRetrieve];
	}
	@catch (NSException *exception)
	{
		EXPLOG(@"[%@ errorUserStream] EXCEPTION\n%@: %@", [self className], [exception name], [exception reason]);
	}
}

@end
