package org.limewire.facebook.service.livemessage;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.limewire.facebook.service.FacebookFriend;
import org.limewire.facebook.service.FacebookFriendConnection;
import org.limewire.facebook.service.FacebookFriendPresence;
import org.limewire.friend.api.FriendPresence;
import org.limewire.friend.api.FriendPresenceEvent;
import org.limewire.friend.api.feature.FeatureInitializer;
import org.limewire.friend.api.feature.FeatureRegistry;
import org.limewire.friend.impl.util.PresenceUtils;
import org.limewire.listener.EventListener;
import org.limewire.listener.ListenerSupport;
import org.limewire.logging.Log;
import org.limewire.logging.LogFactory;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
public class DiscoInfoHandler implements LiveMessageHandler {
private static final Log LOG = LogFactory.getLog(AddressHandler.class);
private static final String REQUEST_TYPE = "disc-info-request";
private static final String RESPONSE_TYPE = "disc-info-response";
private final FacebookFriendConnection connection;
private final FeatureRegistry featureRegistry;
private ListenerSupport<FriendPresenceEvent> availableFriends;
private EventListener<FriendPresenceEvent> friendPresenceListener;
@Inject
DiscoInfoHandler(@Assisted FacebookFriendConnection connection,
FeatureRegistry featureRegistry) {
this.connection = connection;
this.featureRegistry = featureRegistry;
}
@Override
@Inject
public void register(LiveMessageHandlerRegistry registry) {
registry.register(REQUEST_TYPE, this);
registry.register(RESPONSE_TYPE, this);
}
@Inject
public void register(ListenerSupport<FriendPresenceEvent> availableFriends) {
this.availableFriends = availableFriends;
this.friendPresenceListener = new EventListener<FriendPresenceEvent>() {
// listen for known friends instead?
// would result in exchanging disco-info's faster
// but also lots of requests to offline friends
@Override
public void handleEvent(FriendPresenceEvent event) {
LOG.debugf("friend presence event: {0}", event);
if(event.getType() != FriendPresenceEvent.Type.ADDED) {
return;
}
FriendPresence friendPresence = event.getData();
if (!(friendPresence instanceof FacebookFriendPresence)) {
return;
}
FacebookFriend facebookFriend = (FacebookFriend)friendPresence.getFriend();
if (!facebookFriend.hasLimeWireAppInstalled()) {
LOG.debugf("not a limewire friend: {0}", facebookFriend);
return;
}
connection.sendLiveMessage(friendPresence, REQUEST_TYPE, new HashMap<String, Object>());
}
};
this.availableFriends.addListener(friendPresenceListener);
}
public void unregister() {
if (availableFriends != null) {
availableFriends.removeListener(friendPresenceListener);
}
}
private void handleDiscInfoResponse(JSONObject message) throws JSONException, URISyntaxException {
JSONArray features = message.getJSONArray("features");
String from = message.getString("from");
String friendId = PresenceUtils.parseBareAddress(from);
FacebookFriend friend = connection.getFriend(friendId);
if (friend == null) {
LOG.debugf("no friend for id {0}", friendId);
return;
}
FriendPresence presence = friend.getPresences().get(from);
if(presence != null) {
initializePresenceFeatures(presence, features);
} else {
LOG.debugf("presence offline: {0}", from);
}
}
private void handleDiscInfoRequest(JSONObject message) throws JSONException {
String from = message.getString("from");
String friendId = PresenceUtils.parseBareAddress(from);
FacebookFriend friend = connection.getFriend(friendId);
if (friend == null) {
LOG.debugf("disc info from non-friend: {0}", friendId);
return;
}
FriendPresence presence = friend.getPresences().get(from);
if(presence != null) {
List<String> supported = new ArrayList<String>();
for(URI feature : featureRegistry.getPublicFeatureUris()) {
supported.add(feature.toASCIIString());
}
Map<String, Object> response = new HashMap<String, Object>();
response.put("from", connection.getPresenceId());
response.put("features", supported);
connection.sendLiveMessage(presence, RESPONSE_TYPE, response);
} else {
LOG.debugf("disc info from non-friend-presence: {0}", from);
}
}
@Override
public void handle(String messageType, JSONObject message) throws JSONException {
try {
if(messageType.equals(RESPONSE_TYPE)) {
handleDiscInfoResponse(message);
} else if(messageType.equals(REQUEST_TYPE)) {
handleDiscInfoRequest(message);
}
} catch (URISyntaxException e) {
throw new JSONException(e);
}
}
private void initializePresenceFeatures(FriendPresence presence, JSONArray features) throws JSONException, URISyntaxException {
for(int i = 0; i < features.length(); i++) {
String feature = features.getString(i);
FeatureInitializer initializer = featureRegistry.get(new URI(feature));
if (initializer != null) {
initializer.initializeFeature(presence);
}
}
}
}