package com.delect.motiver.server.manager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.delect.motiver.server.cache.TrainingCache;
import com.delect.motiver.server.dao.TrainingDAO;
import com.delect.motiver.server.dao.helper.RoutineSearchParams;
import com.delect.motiver.server.dao.helper.WorkoutSearchParams;
import com.delect.motiver.server.jdo.UserOpenid;
import com.delect.motiver.server.jdo.training.Exercise;
import com.delect.motiver.server.jdo.training.ExerciseName;
import com.delect.motiver.server.jdo.training.Routine;
import com.delect.motiver.server.jdo.training.Workout;
import com.delect.motiver.server.manager.helpers.NameCountWrapper;
import com.delect.motiver.server.util.DateIterator;
import com.delect.motiver.shared.Constants;
import com.delect.motiver.shared.Permission;
import com.delect.motiver.shared.exception.ConnectionException;
import com.prodeagle.java.counters.Counter;
public class TrainingManager extends AbstractManager {
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(TrainingManager.class.getName());
private static final Pattern PATTERN_EXERCISE_TARGET = Pattern.compile("--([0-9])--");
UserManager userManager = UserManager.getInstance();
TrainingCache cache = TrainingCache.getInstance();
TrainingDAO dao = TrainingDAO.getInstance();
private static TrainingManager man;
public static TrainingManager getInstance() {
if(man == null) {
man = new TrainingManager();
}
return man;
}
/**
* Adds single exercise
* @param pm
* @param exercise
* @param uID
* @return
*/
public void addExercise(UserOpenid user, Exercise model, long workoutId) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Adding/updating exercise: "+model);
}
try {
Workout workout = _getWorkout(workoutId);
if(workout != null) {
userManager.checkPermission(Permission.WRITE_TRAINING, user.getUid(), workout.getUid());
//update if found, otherwise add
int i = workout.getExercises().indexOf(model);
Exercise f;
if(i == -1) {
f = model;
workout.getExercises().add(model);
}
else {
f = workout.getExercises().get(i);
f.update(model, false);
}
//reset workout
f.setWorkout(null);
dao.updateWorkout(workout, true);
//return updated model
model.update(f, true);
//find names for each exercise
for(Exercise e : workout.getExercises()) {
if(e.getNameId().longValue() > 0) {
e.setName(_getExerciseName(e.getNameId()));
}
}
if(model.getNameId().longValue() > 0) {
model.setName(_getExerciseName(model.getNameId()));
}
//update cache
if(workout.getDate() != null) {
cache.setWorkouts(new WorkoutSearchParams(workout.getDate(), workout.getUid()), null); //clear day's cache
}
if(workout.getRoutineId() != null) {
cache.removeRoutine(workout.getRoutineId());
}
cache.addWorkout(workout);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error adding exercise", e);
handleException("TrainingManager.addExercise", e);
}
}
/**
* Removes single exercise
* @param pm
* @param exercise
* @param uID
* @return
*/
public boolean removeExercise(UserOpenid user, Exercise model, long workoutId) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Removing exercise: "+model);
}
boolean ok = false;
try {
Workout workout = _getWorkout(workoutId);
if(workout != null) {
userManager.checkPermission(Permission.WRITE_TRAINING, user.getUid(), workout.getUid());
workout.getExercises().remove(model);
dao.updateWorkout(workout, true);
//update cache
if(workout.getDate() != null) {
cache.setWorkouts(new WorkoutSearchParams(workout.getDate(), workout.getUid()), null); //clear day's cache
}
if(workout.getRoutineId() != null) {
cache.removeRoutine(workout.getRoutineId());
}
cache.addWorkout(workout);
}
ok = true;
} catch (Exception e) {
logger.log(Level.SEVERE, "Error adding exercise", e);
handleException("TrainingManager.removeExercise", e);
}
return ok;
}
public List<Workout> getWorkouts(UserOpenid user, Date date, String uid) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading workouts ("+uid+", "+date+")");
}
if(date == null) {
return null;
}
//check permissions
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), uid);
//get from cache
List<Workout> list = null;
try {
WorkoutSearchParams params = new WorkoutSearchParams(date, uid);
//get from cache
Set<Long> keys = cache.getWorkouts(params);
if(keys == null) {
keys = dao.getWorkouts(params);
//add to cache
cache.setWorkouts(params, keys);
}
list = new ArrayList<Workout>();
for(Long key : keys) {
list.add(_getWorkout(key));
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading workouts", e);
handleException("TrainingManager.getWorkouts", e);
}
return list;
}
public Set<Long> getWorkoutsKeys(Date date, String uid) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading workouts keys ("+uid+", "+date+")");
}
if(date == null) {
return null;
}
//get from cache
Set<Long> keys = null;
try {
WorkoutSearchParams params = new WorkoutSearchParams(date, uid);
//get from cache
keys = cache.getWorkouts(params);
if(keys == null) {
keys = dao.getWorkouts(params);
//add to cache
cache.setWorkouts(params, keys);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading workouts keys", e);
handleException("TrainingManager.getWorkouts", e);
}
return keys;
}
public List<Workout> getWorkouts(UserOpenid user, Date dateStart, Date dateEnd, String uid) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading workouts ("+uid+", "+dateStart+" - "+dateEnd+")");
}
//check permissions
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), uid);
Set<Long> keys = new HashSet<Long>();
Iterator<Date> i = new DateIterator(dateStart, dateEnd);
while(i.hasNext())
{
final Date date = i.next();
keys.addAll(getWorkoutsKeys(date, uid));
}
List<Workout> list = new ArrayList<Workout>();
if(keys.size() > 0) {
//get user here, so we can fetch it only once
UserOpenid u = userManager.getUser(uid);
for(Long key : keys) {
Workout w = _getWorkout(key, false);
w.setUser(u);
list.add(w);
}
}
return list;
}
public List<Workout> getWorkouts(UserOpenid user, int offset, String uid) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading workouts ("+offset+", "+uid+")");
}
//check permissions
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), uid);
List<Workout> list = new ArrayList<Workout>();
try {
WorkoutSearchParams params = new WorkoutSearchParams();
params.offset = offset;
params.limit = Constants.LIMIT_WORKOUTS;
params.uid = uid;
Set<Long> keys = dao.getWorkouts(params);
for(Long key : keys) {
Workout jdo = _getWorkout(key);
//can be null if results are cutted
if(jdo != null) {
//check permission
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), jdo.getUid());
}
list.add(jdo);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading workouts", e);
handleException("TrainingManager.getWorkouts", e);
}
return list;
}
public List<Routine> getRoutines(UserOpenid user, int offset, String uid) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading routines ("+offset+", "+uid+")");
}
//check permissions
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), uid);
List<Routine> list = new ArrayList<Routine>();
try {
RoutineSearchParams params = new RoutineSearchParams();
params.offset = offset;
params.limit = Constants.LIMIT_ROUTINES;
params.uid = uid;
List<Long> keys = dao.getRoutines(params);
for(Long key : keys) {
Routine jdo = _getRoutine(key);
//can be null if results are cutted
if(jdo != null) {
//check permission
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), jdo.getUid());
}
list.add(jdo);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading routines", e);
handleException("TrainingManager.getRoutines", e);
}
return list;
}
public List<Workout> getMostPopularWorkouts(UserOpenid user, int offset) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading most popular workouts ("+offset+")");
}
List<Workout> list = new ArrayList<Workout>();
try {
WorkoutSearchParams params = new WorkoutSearchParams();
params.limit = Constants.LIMIT_WORKOUTS * 2;
params.minCopyCount = 1;
//while enough found
int i = 0;
while(list.size() < Constants.LIMIT_WORKOUTS) {
params.offset = i;
Set<Long> keys = dao.getWorkouts(params);
for(Long key : keys) {
if(list.size() == Constants.LIMIT_WORKOUTS) {
break;
}
Workout jdo = _getWorkout(key);
if(jdo != null) {
//check permission
if(userManager.hasPermission(Permission.READ_TRAINING, user.getUid(), jdo.getUid())) {
if(i >= offset) {
list.add(jdo);
}
}
}
}
//if no workouts found -> stop
if(keys.size() == 0) {
break;
}
i += Constants.LIMIT_WORKOUTS * 2;
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading workouts", e);
handleException("TrainingManager.getMostPopularWorkouts", e);
}
return list;
}
public List<Routine> getMostPopularRoutines(UserOpenid user, int offset) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading most popular routines ("+offset+")");
}
List<Routine> list = new ArrayList<Routine>();
try {
RoutineSearchParams params = new RoutineSearchParams();
params.limit = Constants.LIMIT_ROUTINES * 2;
params.minCopyCount = 1;
//while enough found
int i = 0;
while(list.size() < Constants.LIMIT_ROUTINES) {
params.offset = i;
List<Long> keys = dao.getRoutines(params);
for(Long key : keys) {
if(list.size() == Constants.LIMIT_ROUTINES) {
break;
}
Routine jdo = _getRoutine(key);
if(jdo != null) {
//check permission
if(userManager.hasPermission(Permission.READ_TRAINING, user.getUid(), jdo.getUid())) {
if(i >= offset) {
list.add(jdo);
}
}
}
}
//if no routines found -> stop
if(keys.size() == 0) {
break;
}
i += Constants.LIMIT_ROUTINES * 2;
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading routines", e);
handleException("TrainingManager.getMostPopularRoutines", e);
}
return list;
}
public List<Workout> getWorkouts(UserOpenid user, Routine routine, String uid) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading workouts from routine ("+routine+", "+uid+")");
}
//check permissions
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), uid);
List<Workout> list = new ArrayList<Workout>();
try {
//TODO .!!!
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading workouts", e);
handleException("TrainingManager.getWorkouts", e);
}
return list;
}
private Workout _getWorkout(Long key) throws Exception {
return _getWorkout(key, true);
}
/**
* Returns workout based on key
* Fetchs also user and exercises names
* @param key
* @return
* @throws Exception
*/
private Workout _getWorkout(Long key, boolean getUser) throws Exception {
if(logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "_getWorkout ("+key+")");
}
if(key == null) {
return null;
}
Workout jdo = cache.getWorkout(key);
if(jdo == null) {
jdo = dao.getWorkout(key);
//find names for each exercise
for(Exercise f : jdo.getExercises()) {
if(f.getNameId().longValue() > 0) {
f.setName(_getExerciseName(f.getNameId()));
}
}
cache.addWorkout(jdo);
}
if(jdo != null && getUser)
jdo.setUser(userManager.getUser(jdo.getUid()));
//sort exercises
if(jdo != null) {
Collections.sort(jdo.getExercises());
}
return jdo;
}
private Routine _getRoutine(Long routineId) throws Exception {
if(logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "_getRoutine ("+routineId+")");
}
if(routineId == null) {
return null;
}
Routine jdo = cache.getRoutine(routineId);
if(jdo == null) {
jdo = dao.getRoutine(routineId);
//get workouts
Set<Long> keys = dao.getWorkouts(new WorkoutSearchParams(routineId));
ArrayList<Workout> list = new ArrayList<Workout>();
for(Long key : keys) {
list.add(_getWorkout(key));
}
jdo.setWorkouts(list);
cache.addRoutine(jdo);
}
if(jdo != null)
jdo.setUser(userManager.getUser(jdo.getUid()));
return jdo;
}
private ExerciseName _getExerciseName(Long key) throws Exception {
if(logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "_getExerciseName ("+key+")");
}
if(key == null || key == 0) {
return null;
}
ExerciseName jdo = cache.getExerciseName(key);
if(jdo == null) {
jdo = dao.getExerciseName(key);
cache.addExerciseName(jdo);
}
return jdo;
}
private Map<Long, String> _getExerciseNames(String locale) throws Exception {
if(logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "_getExerciseNames");
}
//load from cache
Map<Long, String> mapAll = cache.getExerciseNames(locale);
if(mapAll == null) {
List<ExerciseName> list = dao.getExerciseNames(locale);
//create map
mapAll = new HashMap<Long, String>();
for(ExerciseName name : list) {
mapAll.put(name.getId(), name.getName());
}
//save to cache
cache.setExerciseNames(locale, mapAll);
}
return mapAll;
}
public boolean removeWorkouts(UserOpenid user, List<Workout> models) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Removing workouts: "+models.size());
}
if(models.size() == 0) {
return false;
}
boolean ok = false;
try {
Long[] keys = new Long[models.size()];
//check permission for each workout
int i = 0;
for(Workout workout : models) {
Workout w = _getWorkout(workout.getId());
userManager.checkPermission(Permission.WRITE_TRAINING, user.getUid(), w.getUid());
//remove cache
if(w.getDate() != null) {
cache.setWorkouts(new WorkoutSearchParams(w.getDate(), w.getUid()), null);
}
cache.removeWorkout(w.getId());
keys[i] = w.getId();
i++;
}
//remove all at once
ok = dao.removeWorkouts(keys);
} catch (Exception e) {
logger.log(Level.SEVERE, "Error removing workouts", e);
handleException("TrainingManager.removeWorkouts", e);
}
return ok;
}
public boolean removeRoutines(UserOpenid user, List<Routine> models) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Removing routines: "+models.size());
}
if(models.size() == 0) {
return false;
}
boolean ok = false;
try {
Long[] keys = new Long[models.size()];
//check permission for each routine
int i = 0;
for(Routine routine : models) {
Routine w = _getRoutine(routine.getId());
userManager.checkPermission(Permission.WRITE_TRAINING, user.getUid(), w.getUid());
//remove workouts
//TODO doesn't remove from cache
Set<Long> keysW = dao.getWorkouts(new WorkoutSearchParams(w.getId()));
Long[] keysW2 = keysW.toArray(new Long[0]);
dao.removeWorkouts(keysW2);
//remove from cache
cache.removeRoutine(w.getId());
keys[i] = w.getId();
i++;
}
//remove all at once
ok = dao.removeRoutines(keys);
} catch (Exception e) {
logger.log(Level.SEVERE, "Error removing routines", e);
handleException("TrainingManager.removeRoutines", e);
}
return ok;
}
@SuppressWarnings("deprecation")
public List<Workout> addWorkouts(UserOpenid user, List<Workout> models) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Adding workouts: "+models.size());
}
if(models.size() == 0) {
return null;
}
List<Workout> modelsCopy = new ArrayList<Workout>();
try {
//get workouts
for(Workout workout : models) {
//reset workout from date
Date d = workout.getDate();
if(d != null) {
d.setHours(0);
d.setMinutes(0);
d.setSeconds(0);
workout.setDate(d);
}
Workout clone = null;
//new
if(workout.getId() == 0) {
//add two exercises
List<Exercise> exercises = new ArrayList<Exercise>();
exercises.add(new Exercise());
exercises.add(new Exercise());
workout.setExercises(exercises);
clone = workout;
}
else {
//check cache
Workout jdo = _getWorkout(workout.getId());
//check permission
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), jdo.getUid());
//increment count
if(!user.getUid().equals(jdo.getUid())) {
incrementWorkoutCount(jdo.getId());
}
//add copy
clone = (Workout) jdo.clone();
}
clone.setUid(user.getUid());
clone.setUser(user);
clone.setDate(workout.getDate());
clone.setRoutineId(workout.getRoutineId());
clone.setDayInRoutine(workout.getDayInRoutine());
modelsCopy.add(clone);
//remove cache
if(clone.getDate() != null) {
cache.setWorkouts(new WorkoutSearchParams(clone.getDate(), user.getUid()), null);
}
}
dao.addWorkouts(modelsCopy);
//get workouts
for(int i = 0; i < modelsCopy.size(); i++) {
Workout workout = modelsCopy.get(i);
//clear routine cache
if(workout.getRoutineId() != null) {
cache.removeRoutine(workout.getRoutineId());
}
//get correct workout
//TODO we need to do this because exercise are doubled when adding to db
modelsCopy.set(i, _getWorkout(workout.getId()));
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error adding workouts", e);
handleException("TrainingManager.addWorkouts", e);
}
return modelsCopy;
}
@SuppressWarnings("deprecation")
public List<Routine> addRoutines(UserOpenid user, List<Routine> models) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Adding routines: "+models.size());
}
if(models.size() == 0) {
return null;
}
List<Routine> modelsCopy = new ArrayList<Routine>();
try {
//get routines
for(Routine routine : models) {
Routine clone = null;
//new
if(routine.getId() == 0) {
//default number of days
if(routine.getDays() == 0) {
routine.setDays(Constants.DAYS_ROUTINE_DEFAULT);
}
clone = routine;
clone.setUid(user.getUid());
clone.setUser(user);
clone.setDate(routine.getDate());
dao.addRoutine(clone);
}
else {
//check cache
Routine jdo = _getRoutine(routine.getId());
//check permission
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), jdo.getUid());
//increment count
if(!user.getUid().equals(jdo.getUid())) {
incrementRoutineCount(jdo.getId());
}
//add copy
clone = (Routine) jdo.clone();
clone.setUid(user.getUid());
clone.setUser(user);
clone.setDate(routine.getDate());
dao.addRoutine(clone);
//add workouts
ArrayList<Workout> list = new ArrayList<Workout>();
for(Workout wOld : jdo.getWorkouts()) {
Workout wClone = (Workout) wOld.clone();
//set also date
if(routine.getDate() != null) {
final Date dateNew = new Date( (routine.getDate().getTime() / 1000 + 3600 * 24 * (wClone.getDayInRoutine().intValue() - 1) ) * 1000);
//reset time from date
dateNew.setHours(0);
dateNew.setMinutes(0);
dateNew.setSeconds(0);
wClone.setDate(dateNew);
//clear cache
cache.setWorkouts(new WorkoutSearchParams(dateNew, user.getUid()), null);
}
wClone.setUid(user.getUid());
wClone.setUser(user);
wClone.setRoutineId(clone.getId());
list.add(wClone);
}
dao.addWorkouts(list);
clone.setWorkouts(list);
}
modelsCopy.add(clone);
}
//cache
for(Routine jdo : modelsCopy) {
jdo.setUser(userManager.getUser(jdo.getUid()));
//get workouts
Set<Long> keys = dao.getWorkouts(new WorkoutSearchParams(jdo.getId()));
ArrayList<Workout> list = new ArrayList<Workout>();
for(Long key : keys) {
list.add(_getWorkout(key));
}
jdo.setWorkouts(list);
cache.addRoutine(jdo);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error adding routines", e);
handleException("TrainingManager.addRoutines", e);
}
return modelsCopy;
}
public List<ExerciseName> searchExerciseNames(UserOpenid user, String query, int limit) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Searching exercise names: "+query);
}
long t = System.currentTimeMillis();
List<ExerciseName> list = new ArrayList<ExerciseName>();
try {
//load from cache
Map<Long, String> mapAll = _getExerciseNames(user.getLocale());
if(mapAll != null) {
//split query string
//strip special characters
query = query.replace("(", "");
query = query.replace(")", "");
query = query.replace(",", "");
query = query.toLowerCase();
String[] arr = query.split(" ");
//save
// Set<Integer> targets = new HashSet<Integer>();
// try {
// Matcher matcher = PATTERN_EXERCISE_TARGET.matcher(query);
// while(matcher.find()) {
// targets.add(Integer.parseInt(matcher.group(1)));
// }
// } catch (Exception e1) {
// logger.log(Level.WARNING, "Error parsing target", e1);
// }
//search
List<NameCountWrapper> result = new ArrayList<NameCountWrapper>();
for(Entry<Long, String> entry : mapAll.entrySet()) {
Long id = entry.getKey();
String name = entry.getValue();
//strip special characters
name = name.replace("(", "");
name = name.replace(")", "");
name = name.replace(",", "");
//filter by query (add count variable)
int count = 0;
for(String s : arr) {
//if word long enough
if(s.length() >= Constants.LIMIT_MIN_QUERY_WORD) {
//exact match
if(name.toLowerCase().equals( s )) {
count += 3;
}
//partial match
else if(name.toLowerCase().contains( s )) {
count++;
}
}
}
logger.info(" count: "+count);
//if found
if(count > 0) {
int countUse = 0;
try {
countUse = cache.getExerciseNameCount(user, id);
if(countUse == -1) {
countUse = dao.getExerciseNameCount(user, id);
cache.setExerciseNameCount(user, id, countUse);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error fetching exercise name count", e);
}
NameCountWrapper n = new NameCountWrapper(id, count, countUse);
result.add(n);
}
}
//sort array based on count
Collections.sort(result, NameCountWrapper.COUNT_COMPARATOR);
//convert to client model
for(int i=0; i < result.size() && i < limit; i++) {
NameCountWrapper n = result.get(i);
if(n.countQuery > 0) {
//fetch correct name
list.add(_getExerciseName(n.id));
}
else {
break;
}
//limit query
if(list.size() >= limit) {
break;
}
}
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error searching exercise names", e);
handleException("TrainingManager.searchExerciseNames", e);
}
//prodeagle counter
Counter.increment("Search.ExerciseName.Count");
Counter.increment("Search.ExerciseName.Latency", System.currentTimeMillis()-t);
return list;
}
public List<ExerciseName> addExerciseName(UserOpenid user, List<ExerciseName> names) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Adding exercise names: "+names.size());
}
List<ExerciseName> list = new ArrayList<ExerciseName>();
try {
for(ExerciseName name : names) {
ExerciseName nameOld = _getExerciseName(name.getId());
//add if not found
if(nameOld == null) {
name.setUid(user.getUid());
dao.addExerciseName(name);
}
//otherwise update (if name we have added)
else {
if(nameOld != null
&& (user.getUid().equals(nameOld.getUid()) || user.isAdmin()) ) {
nameOld.update(name, false);
dao.updateExerciseName(nameOld);
}
}
//update "cache" array
cache.addExerciseName(name);
list.add(name);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error adding exercise names", e);
handleException("TrainingManager.addExerciseName", e);
}
return list;
}
public List<Workout> searchWorkouts(UserOpenid user, String query, int index) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Searching workouts ("+query+")");
}
List<Workout> list = new ArrayList<Workout>();
try {
//split query string
String[] arr = query.split(" ");
//load from cache
Set<Long> keysAll = dao.getWorkouts(WorkoutSearchParams.all());
int i = 0;
for(Long key : keysAll) {
Workout m = _getWorkout(key);
if(!m.getUid().equals(user.getUid())
&& userManager.hasPermission(Permission.READ_TRAINING, user.getUid(), m.getUid())) {
if(i >= index) {
final String name = m.getName();
//filter by query
boolean match = false;
for(String s : arr) {
match = name.toLowerCase().contains( s.toLowerCase() );
if(match) {
break;
}
}
if(match) {
list.add(m);
}
}
i++;
}
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error adding exercise names", e);
handleException("TrainingManager.searchWorkouts", e);
}
return list;
}
public List<Routine> searchRoutines(UserOpenid user, String query, int index) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Searching routines ("+query+")");
}
List<Routine> list = new ArrayList<Routine>();
try {
//split query string
String[] arr = query.split(" ");
//load from cache
List<Long> keysAll = dao.getRoutines(RoutineSearchParams.all());
int i = 0;
for(Long key : keysAll) {
Routine m = _getRoutine(key);
if(!m.getUid().equals(user.getUid())
&& userManager.hasPermission(Permission.READ_TRAINING, user.getUid(), m.getUid())) {
if(i >= index) {
final String name = m.getName();
//filter by query
boolean match = false;
for(String s : arr) {
match = name.toLowerCase().contains( s.toLowerCase() );
if(match) {
break;
}
}
if(match) {
list.add(m);
}
}
i++;
}
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error adding exercise names", e);
handleException("TrainingManager.searchRoutines", e);
}
return list;
}
public void updateWorkout(UserOpenid user, Workout model, boolean updateExercises) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Updating workout: "+model);
}
try {
Workout workout = _getWorkout(model.getId());
userManager.checkPermission(Permission.WRITE_TRAINING, user.getUid(), workout.getUid());
//save old date
Date dOld = workout.getDate();
workout.update(model, false, updateExercises);
dao.updateWorkout(workout, updateExercises);
//find names for each exercise
for(Exercise e : workout.getExercises()) {
if(e.getNameId().longValue() > 0) {
e.setName(_getExerciseName(e.getNameId()));
}
}
//update workout given as parameter
model.update(workout, true, updateExercises);
//remove from cache (also old date if moved)
if(workout.getDate() != null) {
cache.setWorkouts(new WorkoutSearchParams(workout.getDate(), workout.getUid()), null);
if(!dOld.equals(workout.getDate())) {
cache.setWorkouts(new WorkoutSearchParams(dOld, workout.getUid()), null);
}
}
cache.removeWorkout(workout.getId());
} catch (Exception e) {
logger.log(Level.SEVERE, "Error updating workout", e);
handleException("TrainingManager.updateWorkout", e);
}
}
public void updateRoutine(UserOpenid user, Routine model) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Updating routine: "+model);
}
try {
Routine routine = dao.getRoutine(model.getId());
userManager.checkPermission(Permission.WRITE_TRAINING, user.getUid(), routine.getUid());
Integer oldDays = routine.getDays();
routine.update(model, false);
dao.updateRoutine(routine);
//update routine given as parameter
model.update(routine, true);
//remove from cache
cache.removeRoutine(routine.getId());
//if days removed -> also remove workouts
if(oldDays > routine.getDays()) {
//get workouts
Set<Long> keys = dao.getWorkouts(new WorkoutSearchParams(routine.getId(), oldDays));
ArrayList<Workout> list = new ArrayList<Workout>();
for(Long key : keys) {
list.add(_getWorkout(key));
}
removeWorkouts(user, list);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error updating routine", e);
handleException("TrainingManager.updateRoutine", e);
}
}
public Workout getWorkout(UserOpenid user, long id) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading single workout: "+id);
}
Workout workout = null;
try {
workout = _getWorkout(id);
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), workout.getUid());
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading workout", e);
handleException("TrainingManager.getWorkout", e);
}
return workout;
}
public ExerciseName getExerciseName(UserOpenid user, long id) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading single exercise name: "+id);
}
ExerciseName name = null;
try {
name = _getExerciseName(id);
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading name", e);
handleException("TrainingManager.getExerciseName", e);
}
return name;
}
public Routine getRoutine(UserOpenid user, long id) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading single routine: "+id);
}
Routine routine = null;
try {
routine = _getRoutine(id);
userManager.checkPermission(Permission.READ_TRAINING, user.getUid(), routine.getUid());
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading routine", e);
handleException("TrainingManager.getRoutine", e);
}
return routine;
}
/**
* Updates exercise order for single workout
*/
public boolean updateExerciseOrder(UserOpenid user, Long workoutId, Long[] ids) throws ConnectionException {
if(logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "Updating exercise order ("+workoutId+", "+ids+")");
}
boolean ok = false;
try {
//get workout
Workout w = _getWorkout(workoutId);
//reorder exercises
for(int i=0; i < ids.length; i++) {
Exercise e = null;
for(Exercise ex : w.getExercises()) {
if(ex.getId().longValue() == ids[i].longValue()) {
e = ex;
break;
}
}
if(e != null) {
e.setOrder(i);
}
else {
ok = false;
}
}
updateWorkout(user, w, true);
ok = true;
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading workout", e);
handleException("TrainingManager.updateExerciseOrder", e);
}
return ok;
}
public void incrementWorkoutCount(long workoutId) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Inrementing workout count: "+workoutId);
}
try {
Workout workout = _getWorkout(workoutId);
dao.incrementWorkoutCount(workout);
//update cache
cache.addWorkout(workout);
} catch (Exception e) {
logger.log(Level.SEVERE, "Error updating workout", e);
handleException("TrainingManager.incrementWorkoutCount", e);
}
}
public void incrementRoutineCount(long routineId) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Inrementing routine count: "+routineId);
}
try {
Routine routine = _getRoutine(routineId);
dao.incrementRoutineCount(routine);
//update cache
cache.addRoutine(routine);
} catch (Exception e) {
logger.log(Level.SEVERE, "Error updating routine", e);
handleException("TrainingManager.incrementRoutineCount", e);
}
}
/**
* Returns exercises which have given nameId from given time period
* @param nameId
* @param dateStart
* @param dateEnd
* @param limit
* @return exercises : sorted by date desc
* @throws ConnectionException
*/
public List<Exercise> getExercises(UserOpenid user, Long nameId, Date dateStart, Date dateEnd, int limit) throws ConnectionException {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading exercises for name "+nameId+", "+dateStart+" - "+dateEnd);
}
if(nameId == null || (dateStart == null && dateEnd == null)) {
return null;
}
long t = System.currentTimeMillis();
List<Exercise> list = new ArrayList<Exercise>();
try {
//if only end date -> get all exercises before that
if(dateStart == null) {
dateStart = new Date( (dateEnd.getTime()/1000 - 3600*24*Constants.LIMIT_EXERCISE_HISTORY_BACK)*1000 );
}
//if only start date -> get all exercises after that
else if(dateEnd == null) {
dateEnd = new Date();
}
Date d1 = null;
Date d2 = dateEnd;
while(list.size() < limit && (d1 == null || d1.getTime() >= dateStart.getTime())) {
//search 14 days at once
d1 = new Date((d2.getTime() / 1000 - 3600 * 24 * 14) * 1000);
//get workouts
List<Workout> workouts = getWorkouts(user, d1, d2, user.getUid());
if(workouts.size() > 0) {
for(int i = workouts.size(); i > 0; i--) {
Workout w = workouts.get(i-1);
if(w != null) {
//check if correct exercise name found
for(Exercise e : w.getExercises()) {
if(e.getNameId() != null && e.getNameId().equals(nameId)) {
e.setWorkout(w);
list.add(e);
}
if(limit != -1 && list.size() >= limit) {
break;
}
}
if(limit != -1 && list.size() >= limit) {
break;
}
}
}
}
d2 = new Date((d1.getTime() / 1000 - 3600 * 24 * 1) * 1000);
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading exercises", e);
handleException("TrainingManager.getExercises", e);
}
//prodeagle counter
Counter.increment("Search.ExerciseHistory.Count");
Counter.increment("Search.ExerciseHistory.Latency", System.currentTimeMillis()-t);
return list;
}
}