package jetbrains.buildServer.serverSide; import com.intellij.openapi.diagnostic.Logger; import jetbrains.buildServer.users.User; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; /** * @author Eugene Petrenko * Created: 31.03.2010 12:42:50 */ public class ChatModel { private final static Logger LOG = Logger.getInstance(ChatModel.class.getName()); private final TimeFactory myTime; private final InitialMessages myInitialMessages; private final Rooms myRooms; private final UserContextFactory myContext; private final Randomization myRandomization; private final Map> myMessages = new ConcurrentHashMap>(); public ChatModel(InitialMessages initialMessages, TimeFactory time, Rooms rooms, UserContextFactory context, Randomization randomization) { myInitialMessages = initialMessages; myTime = time; myRooms = rooms; myContext = context; myRandomization = randomization; } private List getInitialMessages() { return myInitialMessages.getInitialMessages(); } private List getUserMessages(int roomId) { final List chatMessages = myMessages.get(roomId); if(chatMessages == null) { CopyOnWriteArrayList list = new CopyOnWriteArrayList(getInitialMessages()); myMessages.put(roomId, list); return list; } return chatMessages; } public ChatMessagesCollection initializeChat(@Nullable User user) { //Ensure map contains a root final int id = myRooms.getRoomIdByUser(user); getUserMessages(id); return new ChatMessagesCollection(0, Collections.emptyList(), myContext.getUserNamesForUserSession(user), myTime, Collections.singleton(id)); } public ChatMessagesCollection getMessagesToUser(@Nullable User user, int offset) { final int roomId = myRooms.getRoomIdByUser(user); final List pMessages = getUserMessages(roomId); return prepareMessages(user, offset, pMessages, Collections.singleton(roomId)); } public ChatMessagesCollection getAllMessages(int offset) { List allMessages = new ArrayList(); for (List list : myMessages.values()) { allMessages.addAll(list); } Collections.sort(allMessages, new Comparator() { public int compare(ChatMessage o1, ChatMessage o2) { return o1.getDate().compareTo(o2.getDate()); } }); return prepareMessages(null, offset, allMessages, myRooms.getAllRooms()); } private ChatMessagesCollection prepareMessages(@Nullable User user, int offset, List pMessages, Collection rooms) { int i = 0; final List result = new ArrayList(); for (ChatMessage msg : pMessages) { if (i >= offset) { result.add(msg); } i++; } final int nextId = result.isEmpty() ? pMessages.size() : (offset + result.size()); return new ChatMessagesCollection(nextId, result, myContext.getUserNamesForUserSession(user), myTime, rooms); } @NotNull private ChatMessage parseToUser(ChatMessage msg) { String message = msg.getMessage().trim(); if (!message.startsWith("@")) return msg; int space = message.indexOf(' '); if (space <= 0) return msg; final User toUser = myContext.findToUser(message.substring(1, space)); if (toUser == null) return msg; return msg.setToUser(toUser); } private ChatMessage parseBroadcast(ChatMessage msg) { String message = msg.getMessage().trim(); if (!message.startsWith("@all")) return msg; message = message.substring("@all".length()); return msg.setBroadcast(true).setMessage(message); } @Nullable private ChatMessage parseFromUser(ChatMessage msg) { String message = msg.getMessage().trim(); if (!message.startsWith("$")) return msg; int space = message.indexOf(' '); if (space <= 0) return msg; final User fromUser = myContext.findToUser(message.substring(1, space)); if (fromUser == null) return msg; return msg.setFromUser(fromUser).setMessage(message.substring(space+1, message.length())); } private ChatMessage createMessage(User fromUser, String message) { final ChatMessage msg = new ChatMessage(myTime.getTime(), message, fromUser, null); return parseBroadcast(parseToUser(parseFromUser(msg))); } @NotNull public ChatMessagesCollection postMessage(@Nullable User fromUser, String message, int offset) { final ChatMessage msg = createMessage(fromUser, message); User user = msg.getFromUser(); final Set usersRoomId = selectRoomsToPost(msg); myRooms.pingUser(user); for (Integer id : usersRoomId) { LOG.warn(msg.toString()); getUserMessages(id).add(msg); } if (user != null) { scheduleEcho(message, usersRoomId); } return getMessagesToUser(fromUser, offset); } private Set selectRoomsToPost(ChatMessage msg) { User user = msg.getFromUser(); if (user == null || msg.isBroadcast()) { return myRooms.getAllRooms(); } final User toUser = msg.getToUser(); Set set = new HashSet(); set.add(myRooms.getRoomIdByUser(user)); if (toUser != null) { set.add(myRooms.getRoomIdByUser(toUser)); } return set; } private User selectUserForEchoPost(int roomId) { final List mgs = getUserMessages(roomId); if (mgs.size() <= 1) return null; return myRandomization.selectOneOf(mgs, .7).getFromUser(); } private void scheduleEcho(String message, Set roomsToSkip) { final Collection rooms = myRandomization.selectSomeOf(myRooms.getRoomsForEcho(roomsToSkip), 0.05); for (Integer roomId : rooms) { getUserMessages(roomId).add(createMessage(selectUserForEchoPost(roomId), "[[echo]]: " + message)); } } }