/*
* Copyright 2000-2006 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jetbrains.communicator.core.impl.users;
import jetbrains.communicator.core.*;
import jetbrains.communicator.core.transport.TransportEvent;
import jetbrains.communicator.core.users.*;
import jetbrains.communicator.util.StringUtil;
import jetbrains.communicator.util.UIUtil;
import org.picocontainer.Disposable;
import java.util.*;
/**
* @author Kir Maximov
*/
public class UserModelImpl implements UserModel, Disposable {
protected final Collection<User> myUsers = new HashSet<User>();
protected final Collection<String> myGroups = new HashSet<String>();
protected final transient EventBroadcaster myBroadcaster;
private final transient MyListener myEventListener;
private final transient Object myCachedUsersLock = new Object();
protected final transient Object myUsersGroupsLock = new Object();
private transient User[] myCachedUsers;
public UserModelImpl(EventBroadcaster eventBroadcaster) {
myBroadcaster = eventBroadcaster;
myEventListener = new MyListener();
myBroadcaster.addListener(myEventListener);
}
public void dispose() {
myBroadcaster.removeListener(myEventListener);
}
public User createUser(String userName, String transportCode) {
return UserImpl.create(userName, transportCode);
}
public void addUser(final User user) {
if (_getUsers().contains(user)) return;
if (user.isSelf() && !Pico.isUnitTest()) return;
myBroadcaster.doChange(new UserEvent.Added(user), new Runnable() {
public void run() {
synchronized (myUsersGroupsLock) {
myUsers.add(user);
myGroups.add(user.getGroup());
}
}
});
}
public void removeUser(final User user) {
if (!_getUsers().contains(user)) return;
myBroadcaster.doChange(new UserEvent.Removed(user), new Runnable() {
public void run() {
synchronized (myUsersGroupsLock) {
myUsers.remove(user);
}
}
});
}
public String[] getGroups() {
Set<String> result = new TreeSet<String>();
synchronized(myUsersGroupsLock) {
result.addAll(myGroups);
}
String lastGroup = null;
for (User user : getAllUsers()) {
if (!user.getGroup().equals(lastGroup)) {
lastGroup = user.getGroup();
result.add(lastGroup);
}
}
return result.toArray(new String[result.size()]);
}
public User[] getUsers(String groupName) {
List<User> result = new ArrayList<User>();
for (User user : getAllUsers()) {
if (user.getGroup().equals(groupName)) {
result.add(user);
}
}
return result.toArray(new User[result.size()]);
}
public User[] getAllUsers() {
synchronized (myCachedUsersLock) {
if (myCachedUsers == null) {
Collection<User> _users = _getUsers();
myCachedUsers = _users.toArray(new User[_users.size()]);
Arrays.sort(myCachedUsers, new Comparator<User>() {
public int compare(User u1, User u2) {
if (u1.getGroup().equals(u2.getGroup())) {
return UIUtil.compareUsers(u1, u2);
}
return u1.getGroup().compareTo(u2.getGroup());
}
});
}
return myCachedUsers;
}
}
public boolean hasUser(User user) {
synchronized(myUsersGroupsLock) {
return _getUsers().contains(user);
}
}
public String getGroup(User user) {
for (User user1 : _getUsers()) {
if (user1.equals(user)) return user1.getGroup();
}
return null;
}
public void addGroup(String groupName) {
if (StringUtil.isNotEmpty(groupName)) {
final String trimmedName = groupName.trim();
if (Arrays.asList(getGroups()).contains(trimmedName)) return;
myBroadcaster.doChange(new GroupEvent.Added(trimmedName), new Runnable() {
public void run() {
synchronized(myUsersGroupsLock) {
myGroups.add(trimmedName);
}
}
});
}
}
public boolean removeGroup(final String groupName) {
boolean result = false;
User[] users = getUsers(groupName);
for (User user : users) {
removeUser(user);
result = true;
}
synchronized(myUsersGroupsLock) {
if (!myGroups.contains(groupName)) {
return result;
}
}
myBroadcaster.doChange(new GroupEvent.Removed(groupName), new Runnable() {
public void run() {
synchronized (myUsersGroupsLock) {
myGroups.remove(groupName);
}
}
});
return true;
}
public EventBroadcaster getBroadcaster() {
return myBroadcaster;
}
public User findUser(String userName, String transportCode) {
for (User user : _getUsers()) {
if (user.getName().equals(userName) && user.getTransportCode().equals(transportCode)) {
return user;
}
}
return null;
}
public boolean forEach(Object[] nodes, UserAction userAction, boolean considerOnlyOnlineUsers) {
final Set<User> users = new LinkedHashSet<User>();
for (Object node : nodes) {
if (node instanceof User) {
User user = (User) node;
if (!considerOnlyOnlineUsers || user.isOnline()) {
users.add(user);
}
}
else if (node instanceof String) {
forEach(getUsers(node.toString()), new UserAction() {
public boolean executeAndContinue(User user) {
users.add(user);
return true;
}
}, considerOnlyOnlineUsers);
}
else {
throw new IllegalArgumentException("Invalid nodes: " + Arrays.asList(nodes));
}
}
for (User user : users) {
if (!userAction.executeAndContinue(user)) {
return false;
}
}
return true;
}
public String renameGroup(final String oldGroup, String newGroup) {
final User[] users = getUsers(oldGroup);
final String newName = StringUtil.fixGroup(newGroup);
myBroadcaster.doChange(new GroupEvent.Updated(oldGroup, newName), new Runnable() {
public void run() {
synchronized(myUsersGroupsLock) {
myGroups.remove(oldGroup);
for (final User user : users) {
user.setGroup(newName, null);
}
myGroups.add(newName);
}
}
});
return newName;
}
private Collection<User> _getUsers() {
synchronized(myUsersGroupsLock) {
return new HashSet<User>(myUsers);
}
}
private class MyListener extends IDEtalkAdapter {
public void afterChange(IDEtalkEvent event) {
event.accept(new EventVisitor(){
@SuppressWarnings({"RefusedBequest"})
@Override public void visitTransportEvent(TransportEvent event) {
addUser(event.createUser(UserModelImpl.this));
}
@Override public void visitUserEvent(UserEvent event) {
super.visitUserEvent(event);
synchronized(myCachedUsersLock) {
myCachedUsers = null;
}
}
});
}
}
}