001 // License: GPL. Copyright 2007 by Immanuel Scholz and others
002 package org.openstreetmap.josm.data.osm;
003
004 import static org.openstreetmap.josm.tools.I18n.tr;
005
006 import java.util.ArrayList;
007 import java.util.HashMap;
008 import java.util.HashSet;
009 import java.util.List;
010 import java.util.concurrent.atomic.AtomicLong;
011
012 import org.openstreetmap.josm.tools.Utils;
013
014 /**
015 * A simple class to keep a list of user names.
016 *
017 * Instead of storing user names as strings with every OSM primitive, we store
018 * a reference to an user object, and make sure that for each username there
019 * is only one user object.
020 *
021 *
022 */
023 public class User {
024
025 static private AtomicLong uidCounter = new AtomicLong();
026
027 /**
028 * the map of known users
029 */
030 private static HashMap<Long,User> userMap = new HashMap<Long,User>();
031 private final static User anonymous = createLocalUser(tr("<anonymous>"));
032
033 private static long getNextLocalUid() {
034 return uidCounter.decrementAndGet();
035 }
036
037 /**
038 * Creates a local user with the given name
039 *
040 * @param name the name
041 */
042 public static User createLocalUser(String name) {
043 for(long i = -1; i >= uidCounter.get(); --i)
044 {
045 User olduser = getById(i);
046 if(olduser != null && olduser.hasName(name))
047 return olduser;
048 }
049 User user = new User(getNextLocalUid(), name);
050 userMap.put(user.getId(), user);
051 return user;
052 }
053
054 /**
055 * Creates a user known to the OSM server
056 *
057 * @param uid the user id
058 * @param name the name
059 */
060 public static User createOsmUser(long uid, String name) {
061 User user = userMap.get(uid);
062 if (user == null) {
063 user = new User(uid, name);
064 userMap.put(user.getId(), user);
065 }
066 if (name != null) user.addName(name);
067 return user;
068 }
069
070 /**
071 * clears the static map of user ids to user objects
072 *
073 */
074 public static void clearUserMap() {
075 userMap.clear();
076 }
077
078 /**
079 * Returns the user with user id <code>uid</code> or null if this user doesn't exist
080 *
081 * @param uid the user id
082 * @return the user; null, if there is no user with this id
083 */
084 public static User getById(long uid) {
085 return userMap.get(uid);
086 }
087
088 /**
089 * Returns the list of users with name <code>name</code> or the empty list if
090 * no such users exist
091 *
092 * @param name the user name
093 * @return the list of users with name <code>name</code> or the empty list if
094 * no such users exist
095 */
096 public static List<User> getByName(String name) {
097 if (name == null) {
098 name = "";
099 }
100 List<User> ret = new ArrayList<User>();
101 for (User user: userMap.values()) {
102 if (user.hasName(name)) {
103 ret.add(user);
104 }
105 }
106 return ret;
107 }
108
109 public static User getAnonymous() {
110 return anonymous;
111 }
112
113 /** the user name */
114 private final HashSet<String> names = new HashSet<String>();
115 /** the user id */
116 private final long uid;
117
118 /**
119 * Replies the user name
120 *
121 * @return the user name. Never null, but may be the empty string
122 */
123 public String getName() {
124 return Utils.join("/", names);
125 }
126
127 /**
128 * Returns the list of user names
129 *
130 * @returns list of names
131 */
132 public ArrayList<String> getNames() {
133 return new ArrayList<String>(names);
134 }
135
136 /**
137 * Adds a user name to the list if it is not there, yet.
138 *
139 * @param name
140 */
141 public void addName(String name) {
142 names.add(name);
143 }
144
145 /**
146 * Returns true if the name is in the names list
147 *
148 * @param name
149 */
150 public boolean hasName(String name) {
151 return names.contains(name);
152 }
153
154 /**
155 * Replies the user id. If this user is known to the OSM server the positive user id
156 * from the server is replied. Otherwise, a negative local value is replied.
157 *
158 * A negative local is only unique during an editing session. It is lost when the
159 * application is closed and there is no guarantee that a negative local user id is
160 * always bound to a user with the same name.
161 *
162 */
163 public long getId() {
164 return uid;
165 }
166
167 /** private constructor, only called from get method. */
168 private User(long uid, String name) {
169 this.uid = uid;
170 if (name != null) {
171 addName(name);
172 }
173 }
174
175 public boolean isOsmUser() {
176 return uid > 0;
177 }
178
179 public boolean isLocalUser() {
180 return uid < 0;
181 }
182
183 @Override
184 public int hashCode() {
185 final int prime = 31;
186 int result = 1;
187 result = prime * result + getName().hashCode();
188 result = prime * result + (int) (uid ^ (uid >>> 32));
189 return result;
190 }
191
192 @Override
193 public boolean equals(Object obj) {
194 if (! (obj instanceof User))
195 return false;
196 User other = (User) obj;
197 if (uid != other.uid)
198 return false;
199 return true;
200 }
201
202 @Override
203 public String toString() {
204 StringBuffer s = new StringBuffer();
205 s.append("id:"+uid);
206 if (names.size() == 1) {
207 s.append(" name:"+getName());
208 }
209 else if (names.size() > 1) {
210 s.append(String.format(" %d names:%s", names.size(), getName()));
211 }
212 return s.toString();
213 }
214 }