#import "JubChatClient.h"
#import "ObjXMPP/namespaces.h"

#import "JubAvatarManager.h"

#define JUB_CLIENT_URI @"http://babelmonkeys.de/jubjub"

@implementation JubChatClient
@synthesize connection = _connection;
@synthesize roster = _roster;
@synthesize avatarManager = _avatarManager;
@synthesize contactManager = _contactManager;
@synthesize discoEntity = _discoEntity;
@synthesize presence = _presence;
@synthesize ui = _ui;

- initWithConfig: (JubConfig*)config
{
	self = [super init];

	@try {
		_chatMap = [[OFMutableDictionary alloc] init];

		_connection = [XMPPConnection new];
		_connection.username = config.username;
		_connection.domain = config.domain;
		_connection.server = config.server;
		_connection.password = config.password;
		[_connection addDelegate: self];

		_roster = [[XMPPRoster alloc] initWithConnection: _connection];
		[_roster addDelegate: self];

		_discoEntity =
		    [[XMPPDiscoEntity alloc] initWithConnection: _connection
						       capsNode: JUB_CLIENT_URI];

		XMPPDiscoIdentity *identity =
		    [XMPPDiscoIdentity identityWithCategory: @"client"
						       type: @"pc"
						       name: @"JubJub"];
		[_discoEntity addIdentity: identity];
		[_discoEntity addFeature: XMPP_NS_CAPS];

		_avatarManager =
		    [[JubAvatarManager alloc] initWithClient: self];

		_contactManager = [[XMPPContactManager alloc]
		    initWithConnection: _connection
				roster: _roster];
		[_contactManager addDelegate: self];

		_streamManagement = [[XMPPStreamManagement alloc]
		    initWithConnection: _connection];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_roster removeDelegate: self];
	[_contactManager removeDelegate: self];
	[_connection removeDelegate: self];

	[_roster release];
	[_contactManager release];
	[_discoEntity release];
	[_streamManagement release];
	[_avatarManager release];
	[_connection release];
	[_presence release];
	[_chatMap release];

	[super dealloc];
}

- (id<JubChatUI>)chatForContact: (XMPPContact*)contact
{
	OFAutoreleasePool *pool = [OFAutoreleasePool new];
	OFString *bareJID = [contact.rosterItem.JID bareJID];

	id<JubChatUI> chat = [_chatMap objectForKey: bareJID];
	if (chat == nil) {
		OFString * title =
		    [@"Chat with " stringByAppendingString: bareJID];

		chat = [[[[_ui chatUIClass] alloc]
		    initWithTitle: title
		       closeBlock: ^{
				[_chatMap removeObjectForKey: bareJID];
			}
			sendBlock: ^(OFString *text) {
				XMPPMessage *msg =
				    [XMPPMessage messageWithType: @"chat"];
				msg.body = text;
				[contact sendMessage: msg
					  connection: _connection];
			}
		] autorelease];

		[_chatMap setObject: chat
			     forKey: bareJID];
	}

	[pool release];

	return chat;
}

- (void)sendPresenceWithStatus: (OFString*)status
{
	[self sendPresenceWithStatus: status
				text: nil];
}

- (void)sendPresenceWithStatus: (OFString*)status
			  text: (OFString*)text
{
	XMPPPresence *presence;

	if ([status isEqual: @"unavailable"])
		presence = [XMPPPresence presenceWithType: @"unavailable"];
	else
		presence = [XMPPPresence presence];

	if (!([status isEqual: @"available"] ||
	      [status isEqual: @"unavailable"]))
		presence.show = status;

	if (text != nil)
		presence.status = text;

	OFXMLElement *caps = [OFXMLElement elementWithName: @"c"
						 namespace: XMPP_NS_CAPS];
	[caps addAttributeWithName: @"hash"
		       stringValue: @"sha-1"];
	[caps addAttributeWithName: @"ver"
		       stringValue: [_discoEntity capsHash]];
	[caps addAttributeWithName: @"node"
		       stringValue: JUB_CLIENT_URI];

	[presence addChild: caps];

	[_connection sendStanza: presence];
}

- (void)connection: (XMPPConnection*)connection
     wasBoundToJID: (XMPPJID*)jid
{
	[_roster requestRoster];
}

-   (void)connection: (XMPPConnection*)connection
  didReceivePresence: (XMPPPresence*)presence
{
	if ([presence.from isEqual: connection.JID]) {
		[_ui         client: self
		  didChangePresence: presence];
		OF_SETTER(_presence, presence, true, 0);
	}
}

-  (void)contact: (XMPPContact*)contact
  didSendMessage: (XMPPMessage*)message
{
	if (message.body == nil || ![message.type isEqual: @"chat"])
		return;

	id<JubChatUI> chat = [self chatForContact: contact];
	[chat addMessage: message.body
		  sender: [message.from bareJID]];
}

- (void)rosterWasReceived: (XMPPRoster*)roster
{
	[self sendPresenceWithStatus: @"available"
				text: @"Hello from JubJub"];
}
@end
