/*******************************************************************************
* Copyright 2011 Antti Havanko
*
* This file is part of Motiver.fi.
* Motiver.fi is licensed under one open source license and one commercial license.
*
* Commercial license: This is the appropriate option if you want to use Motiver.fi in
* commercial purposes. Contact license@motiver.fi for licensing options.
*
* Open source license: This is the appropriate option if you are creating an open source
* application with a license compatible with the GNU GPL license v3. Although the GPLv3 has
* many terms, the most important is that you must provide the source code of your application
* to your users so they can be free to modify your application for their own needs.
******************************************************************************/
package com.delect.motiver.client.presenter.training;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.http.client.Request;
import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.delect.motiver.client.AppController;
import com.delect.motiver.client.Motiver;
import com.delect.motiver.client.MyAsyncCallback;
import com.delect.motiver.client.event.ExerciseCreatedEvent;
import com.delect.motiver.client.event.ExerciseRemovedEvent;
import com.delect.motiver.client.event.ExerciseUpdatedEvent;
import com.delect.motiver.client.presenter.Presenter;
import com.delect.motiver.client.presenter.training.ExerciseNameEditorPresenter.ExerciseNameEditorDisplay;
import com.delect.motiver.client.presenter.training.ExerciseNameEditorPresenter.ExerciseNameEditorHandler;
import com.delect.motiver.client.presenter.training.SingleExerciseHistoryPresenter.SingleExerciseHistoryDisplay;
import com.delect.motiver.client.service.MyServiceAsync;
import com.delect.motiver.client.view.Display;
import com.delect.motiver.client.view.training.ExerciseNameEditorView;
import com.delect.motiver.client.view.training.SingleExerciseHistoryView;
import com.delect.motiver.shared.Constants;
import com.delect.motiver.shared.ExerciseModel;
import com.delect.motiver.shared.ExerciseNameModel;
import com.delect.motiver.shared.WorkoutModel;
/**
* Shows single exercise
* @author Antti
*
*/
public class ExercisePresenter extends Presenter implements Comparable<ExercisePresenter> {
/**
* Abstract class for view to extend
*/
public abstract static class ExerciseDisplay extends Display {
public abstract ExerciseModel getExercise();
public abstract void setHandler(ExerciseHandler exerciseHandler);
public abstract void setModel(ExerciseModel exercise);
public abstract void setNameComboEnabled(boolean b);
}
public interface ExerciseHandler {
void exerciseRemoved();
void newNameEntered(String newName); //when new name is typed
void query(String query, AsyncCallback<List<ExerciseNameModel>> callback); //called when user search for exercises (names)
void saveData(ExerciseModel mode, boolean nameChanged);
void showLastWeights();
void showVideo();
}
private ExerciseDisplay display;
//child presenters
private ExerciseNameEditorPresenter exerciseNameEditorPresenter;
private String lastQuery = "";
private SingleExerciseHistoryPresenter lastWeightsPresenter;
protected ExerciseModel exercise;
private Timer timerUpdate;
public ExercisePresenter(MyServiceAsync rpcService, SimpleEventBus eventBus, ExerciseDisplay display, ExerciseModel exercise, WorkoutModel workout) {
super(rpcService, eventBus);
this.display = display;
exercise.setWorkout(workout);
this.exercise = exercise;
}
@Override
public int compareTo(ExercisePresenter compare) {
return exercise.compareTo(compare.exercise);
}
@Override
public Display getView() {
return display;
}
@Override
public void onBind() {
display.setModel(exercise);
if(exercise.getId() != 0) {
display.setContentEnabled(true);
//event handler (fire event)
display.setHandler(new ExerciseHandler() {
@Override
public void exerciseRemoved() {
display.setContentEnabled(false);
List<ExerciseModel> list = new ArrayList<ExerciseModel>();
list.add(exercise);
final Request req = rpcService.removeExercises(list, new MyAsyncCallback<Boolean>() {
@Override
public void onSuccess(Boolean ok) {
stop();
if(ok) {
eventBus.fireEvent(new ExerciseRemovedEvent(exercise));
}
}
});
addRequest(req);
}
@Override
public void newNameEntered(String newName) {
//if presenter already visible -> cancel
if(exerciseNameEditorPresenter != null) {
return;
}
//hide last weights
if(lastWeightsPresenter != null) {
lastWeightsPresenter.stop();
lastWeightsPresenter = null;
}
//disable combo
display.setNameComboEnabled(false);
//create dummy model
ExerciseNameModel model = new ExerciseNameModel(0L, newName, 0);
//new name typed -> launch NewExerciseNamePresenter
exerciseNameEditorPresenter = new ExerciseNameEditorPresenter(rpcService, eventBus, (ExerciseNameEditorDisplay)GWT.create(ExerciseNameEditorView.class), model);
exerciseNameEditorPresenter.run(display.getBaseContainer());
//refresh view when name set / edit cancelled
exerciseNameEditorPresenter.setHandler(new ExerciseNameEditorHandler() {
@Override
public void editCancelled() {
//enable combo
display.setNameComboEnabled(true);
//reset model
display.setModel(exercise);
exerciseNameEditorPresenter = null;
}
@Override
public void nameSaved(ExerciseNameModel model) {
//enable combo
display.setNameComboEnabled(true);
exerciseNameEditorPresenter = null;
exercise.setName(model);
//update exercise
updateExercise(true);
}
});
}
@Override
public void query(String query, final AsyncCallback<List<ExerciseNameModel>> callback) {
query = query.toLowerCase();
// //parse query name (transfer equipment's name to index)
// for(int i=1; i < AppController.LangConstants.Targets().length; i++) {
// String t = AppController.LangConstants.Targets()[i].toLowerCase();
// RegExp re = RegExp.compile("(^|[^a-z])"+t+"($|[^a-z])");
// query = re.replace(query, " --" + i + "-- ");
// }
//trim
final String queryTrimmed = query.trim();
//save query
lastQuery = queryTrimmed;
Motiver.setNextCallCacheable(true);
final Request req = rpcService.searchExerciseNames(queryTrimmed, Constants.LIMIT_SEARCH_NAMES, new MyAsyncCallback<List<ExerciseNameModel>>() {
@Override
public void onSuccess(List<ExerciseNameModel> result) {
//only if last query
if(queryTrimmed.equals(lastQuery)) {
callback.onSuccess(result);
}
}
});
addRequest(req);
}
@Override
public void saveData(ExerciseModel model, boolean nameChanged) {
exercise = model;
updateExercise(nameChanged);
//if name changed -> refresh last weights
if(nameChanged && lastWeightsPresenter != null) {
lastWeightsPresenter.stop();
lastWeightsPresenter = null;
showLastWeightsPresenter();
}
}
@Override
public void showLastWeights() {
showLastWeightsPresenter();
}
@Override
public void showVideo() {
//open video in new window
if(exercise.getName() != null) {
String url = exercise.getName().getVideo();
if(!url.contains("http://")) {
url = "http://" + url;
}
Window.open(url, "Video for " + exercise.getName().getName(), "");
}
}
});
}
}
@Override
public void onRun() {
//if no exercise -> create new one
if(exercise.getId() == 0) {
display.setContentEnabled(false);
final Request req = rpcService.addExercise(exercise, new MyAsyncCallback<ExerciseModel>() {
@Override
public void onSuccess(ExerciseModel result) {
if(result != null) {
display.setContentEnabled(true);
//set data
exercise.setId(result.getId());
//fire event
eventBus.fireEvent(new ExerciseCreatedEvent(exercise));
//refresh
display.setModel(exercise);
run(display.getBaseContainer());
}
}
});
addRequest(req);
}
}
@Override
public void onStop() {
if(exerciseNameEditorPresenter != null) {
exerciseNameEditorPresenter.stop();
}
if(lastWeightsPresenter != null) {
lastWeightsPresenter.stop();
}
}
/**
* Shows last weights presenter. Hides presenter if it is already visible
*/
protected void showLastWeightsPresenter() {
if(exercise.getName() != null) {
if(lastWeightsPresenter == null) {
//if no date -> show exercise before today
Date date = (exercise.getDate() != null)? exercise.getDate() : new Date();
//remove one day
date = new Date( date.getTime() - 1000 * 3600 * 24 );
lastWeightsPresenter = new SingleExerciseHistoryPresenter(rpcService, eventBus, (SingleExerciseHistoryDisplay)GWT.create(SingleExerciseHistoryView.class), exercise.getName().getId(), null, date, Constants.LIMIT_LAST_WEIGHTS);
lastWeightsPresenter.run(display.getBaseContainer());
}
else {
lastWeightsPresenter.stop();
lastWeightsPresenter = null;
}
}
}
/**
* Updates exercise from server based to model-variable
* Fires ExerciseUpdatedEvent
*/
protected void updateExercise(final boolean nameChanged) {
if(timerUpdate != null)
timerUpdate.cancel();
if(nameChanged) {
display.setModel(exercise);
}
timerUpdate = new Timer() {
@Override
public void run() {
//save date from exercise
final Date date = exercise.getDate();
rpcService.updateExercise(exercise, new MyAsyncCallback<ExerciseModel>() {
@Override
public void onSuccess(ExerciseModel result) {
if(result != null && display != null) {
//set data
result.setWorkoutId(exercise.getWorkoutId());
//update model
exercise = result;
//restore date
exercise.setDate(date);
if(nameChanged) {
display.setModel(exercise);
}
}
}
});
}
};
timerUpdate.schedule(Constants.DELAY_MODEL_UPDATE);
eventBus.fireEvent(new ExerciseUpdatedEvent(exercise));
}
public void setModel(ExerciseModel ex) {
exercise = ex;
display.setModel(exercise);
}
}