package gotnames.web.st;
import gotnames.Utils;
import gotnames.dm.Guess;
import gotnames.dm.User;
import gotnames.dm.User.Gender;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import com.medallia.tiny.Clock;
import com.medallia.tiny.CollUtils;
import com.medallia.tiny.Empty;
import com.medallia.tiny.Func;
import com.medallia.tiny.Funcs;
import com.medallia.tiny.Predicate;
/**
* Task which generates the form received by {@link CheckGuessTask}. It displays
* a row of pictures (see {@link #NUM_PEOPLE}) with a set of names below each
* picture. The user can pick one of the names for each picture before
* submitting the form.
*/
public class GuessNamesTask extends GotNamesTask {
/** How many people to display */
public static final int NUM_PEOPLE = 4;
@Output interface Values {
V<List<GuessWebView>> PEOPLE = v();
}
PostAction action(final User loggedInUser, DynamicInput dynamicInput, PersistenceManager pm) {
final Date now = Clock.now();
// Obtain a list of all users in the group, excluding the logged in users
Collection<User> allUsers = getAllUsersExceptSelf(pm, loggedInUser);
Query q = pm.newQuery(Guess.class);
q.setFilter("userKey == " + loggedInUser.getKey());
Collection<Guess> guesses = Utils.cast(q.execute());
final Map<Long, Guess> guessByCorrectUser = Funcs.buildMap(guesses, Guess.CORRECT_USER_FUNC);
List<User> candidateUsers = CollUtils.filteredCopy(allUsers, new Predicate<User>() {
@Override public boolean accept(User u) {
// Remove users without profile picture
if (!u.isProfilePicture())
return false;
// Remove any users which have been guessed 'recently'
Guess guess = guessByCorrectUser.get(u.getKey());
if (guess != null && !Guess.guessAllowed(now, guess))
return false;
return true;
}
});
if (candidateUsers.isEmpty())
return template("noGuesses");
// Select randomly by shuffling the list and then picking from the top
Collections.shuffle(candidateUsers);
// The options must match the gender of the person being guessed
final Map<Gender, List<User>> usersByGender = getUsersByGender(allUsers);
attr(Values.PEOPLE, Funcs.map(Utils.subList(NUM_PEOPLE, candidateUsers), new Func<User, GuessWebView>() {
private int counter = 0;
@Override public GuessWebView call(final User u) {
final int index = counter++;
return new GuessWebView() {
@Override public int getIndex() {
return index;
}
@Override public User getUser() {
return u;
}
@Override public List<User> getOptions() {
// Options are only of the same gender
List<User> options = Empty.list(usersByGender.get(u.getGender()));
// Remove to avoid the correct answer appearing twice
options.remove(u);
// Shuffle and pick top 5
Collections.shuffle(options);
options = Utils.subList(5, options);
// Add the correct option back and re-shuffle
options.add(u);
Collections.shuffle(options);
return options;
}
};
}
}));
return null;
}
private Map<Gender, List<User>> getUsersByGender(Collection<User> users) {
final Map<Gender, List<User>> usersByGender = Funcs.partition(users, new Func<User, Gender>() {
@Override public Gender call(User u) {
return u.getGender();
}
});
for (Gender g : Gender.values())
if (!usersByGender.containsKey(g))
usersByGender.put(g, Collections.<User>emptyList());
return usersByGender;
}
private Collection<User> getAllUsersExceptSelf(PersistenceManager pm, User user) {
Query q = pm.newQuery(User.class);
q.setFilter("key != " + user.getKey() + " && groupKey == " + user.getGroupKey());
return Utils.cast(q.execute());
}
/** Used to render each picture */
public interface GuessWebView {
int getIndex();
User getUser();
List<User> getOptions();
}
@Override public String getPageTitle() { return "Guess names"; }
}