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    }