package de.tud.kom.socom.web.client.influence;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.json.client.JSONException;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.safehtml.shared.SafeUri;
import com.google.gwt.safehtml.shared.UriUtils;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.RootPanel;
import de.tud.kom.socom.web.client.AppController;
import de.tud.kom.socom.web.client.AppController.PageElementIDs;
import de.tud.kom.socom.web.client.administration.itemadministration.ViewWithItemAdministration;
import de.tud.kom.socom.web.client.baseelements.AbstractMainPresenter;
import de.tud.kom.socom.web.client.baseelements.MainPresenter;
import de.tud.kom.socom.web.client.baseelements.ViewInterface;
import de.tud.kom.socom.web.client.baseelements.ViewWithErrorsInterface;
import de.tud.kom.socom.web.client.baseelements.viewerrors.ErrorCodeUnknownTypeView;
import de.tud.kom.socom.web.client.baseelements.viewerrors.ErrorIllegalDurationNumberView;
import de.tud.kom.socom.web.client.baseelements.viewerrors.ErrorLoginNeededView;
import de.tud.kom.socom.web.client.baseelements.viewerrors.ErrorNotYetStartedView;
import de.tud.kom.socom.web.client.baseelements.viewerrors.ErrorSelectionRestrictionView;
import de.tud.kom.socom.web.client.baseelements.viewerrors.ErrorServerUnknownErrorView;
import de.tud.kom.socom.web.client.baseelements.viewerrors.ErrorView;
import de.tud.kom.socom.web.client.baseelements.viewerrors.ErrorViewFactory;
import de.tud.kom.socom.web.client.baseelements.viewerrors.ErrorVisibilityViolationView;
import de.tud.kom.socom.web.client.baseelements.viewinfos.InfoInfluenceAlreadyFinishedView;
import de.tud.kom.socom.web.client.eventhandler.FormSubmitCompleteEventHandler;
import de.tud.kom.socom.web.client.eventhandler.FormSubmitEventHandler;
import de.tud.kom.socom.web.client.eventhandler.FormValueChangeEventHandler;
import de.tud.kom.socom.web.client.eventhandler.HasFormSubmitCompleteHandlers;
import de.tud.kom.socom.web.client.eventhandler.HasFormSubmitHandlers;
import de.tud.kom.socom.web.client.eventhandler.HasFormValueChangeHandlers;
import de.tud.kom.socom.web.client.eventhandler.LoginEventHandler;
import de.tud.kom.socom.web.client.events.FormSubmitCompleteEvent;
import de.tud.kom.socom.web.client.events.FormSubmitEvent;
import de.tud.kom.socom.web.client.events.FormValueChangeEvent;
import de.tud.kom.socom.web.client.events.LoginErrorNetworkUserNotFoundEvent;
import de.tud.kom.socom.web.client.events.LoginErrorWrongUserIDPasswortEvent;
import de.tud.kom.socom.web.client.events.LoginEvent;
import de.tud.kom.socom.web.client.events.LogoutEvent;
import de.tud.kom.socom.web.client.events.FormValueChangeEvent.ChangeType;
import de.tud.kom.socom.web.client.influence.image.AnswerImage;
import de.tud.kom.socom.web.client.influence.image.InfluenceAnswerImageView;
import de.tud.kom.socom.web.client.influence.strategies.AudioInfluenceStrategy;
import de.tud.kom.socom.web.client.influence.strategies.ImageInfluenceStrategy;
import de.tud.kom.socom.web.client.influence.strategies.InfluenceStrategy;
import de.tud.kom.socom.web.client.influence.strategies.TextInfluenceStrategy;
import de.tud.kom.socom.web.client.reporting.ViewWithItemReporting;
import de.tud.kom.socom.web.client.services.influence.SoComInfluenceServiceAsync;
import de.tud.kom.socom.web.client.sharedmodels.Influence;
import de.tud.kom.socom.web.client.sharedmodels.InfluenceAnswer;
import de.tud.kom.socom.web.client.sharedmodels.SimpleEntry;
import de.tud.kom.socom.web.client.util.FileUtils.FileState;
import de.tud.kom.socom.web.client.util.exceptions.NotVisibleException;
@SuppressWarnings({ "unchecked", "rawtypes" })
public class InfluencePresenter extends AbstractMainPresenter implements MainPresenter, LoginEventHandler,
FormValueChangeEventHandler, FormSubmitEventHandler, FormSubmitCompleteEventHandler
{
private static final String INFLUENCE_COOKIE = "influences";
public interface InfluenceViewInterface extends ViewWithErrorsInterface {
public void showCountdown(Date timeout);
public void setQuestion(String question);
public void setAnswerColumns(int maxcolumns);
public <T extends Object> void setPossibleAnswers(List<InfluenceAnswerViewInterface<T>> answers);
public <T extends Object> List<InfluenceAnswerViewInterface<T>> getSelectedAnswers();
public void disableSubmit();
public void enableSubmit();
public void showSubmit(boolean show);
public void setAdministrationVisible(boolean visible);
public <T extends Object> void appendAnswer(InfluenceAnswerViewInterface<T> freeAnswerView);
public void replaceAnswers(InfluenceFreeAnswerViewInterface<AnswerImage> oldAnswerView,
InfluenceAnswerImageView newAnswerView, boolean appendOld, boolean selected);
}
public interface InfluenceAnswerViewInterface<T> extends ViewInterface, HasFormValueChangeHandlers,
ViewWithItemAdministration, ViewWithItemReporting {
public void setAnswer(T answer);
public void setFromUser(long userId, String userName, Date created);
/** this calls switchResultView(true) as well automatically */
public void setResultInformation(int totalnumberOfVotes, int numberOfVotes, boolean isWinner);
public boolean isSelected();
public <H extends EventHandler> HandlerRegistration addHandler(final H handler, GwtEvent.Type<H> type);
/** toggles View to show the Resultview or Vote View */
void switchResultView(boolean showResultView);
/**
* returns the current state of loading/displaying the answer. mostly
* useful if a binary file is type of Answer which may be not found or
* still loading etc.
*/
FileState getReadyState();
public void setVotable(boolean votable);
public void setSelected(boolean selected);
public void animate();
}
public interface InfluenceFreeAnswerViewInterface<T> extends InfluenceAnswerViewInterface<T>,
HasFormSubmitHandlers, HasFormSubmitCompleteHandlers {
public T getFreeAnswerValue();
public void disableAddAnswer();
}
public interface InfluenceFreeAnswerWithFileViewInterface<T> extends InfluenceFreeAnswerViewInterface<T>
{
/**
* if the InfluenceFreeAnswer has an associated file it uploads the file
* via form. Caller can register an FormSubmitHandler and/or
* FormSubmitCompleteEventHandler to be informed of
* started/finished/ended uploads
*
* @param action
* the URL to post the file to
* @param hiddenParameters
* (optional) can be NULL. if set, each key=value pair is
* submitted as hidden parameters with form on submit
* @param type
* change type to distinguish between file and file_drag if necessary
*/
public void submitFile(SafeUri action, SimpleEntry<String, String>... hiddenParameters);
public void submitFile(ChangeType type, SafeUri action, SimpleEntry<String, String>... hiddenParameters);
/**
* enables or disables the Submit element for user; submitFile() can
* still be called and will submit though
*/
public void setSubmitEnabled(boolean enabled);
}
/** which types of answers are currently presented and displayed to user */
// package protected for use with other InfluencePresenters and Views..
enum MODE
{
text, image, audio
}
protected static final long PERIOD_MILLIS_FOR_COUNTDOWN_VISIBLE = 10 * 60 * 1000; // 10minutes
private static InfluencePresenter instance;
private InfluenceViewInterface view;
private SoComInfluenceServiceAsync influenceService;
private InfluenceStrategy strategy;
private Influence influence;
public short minOptions = 1;
public short maxOptions = 1;
private short currentlySelectedOptions = 0;
private long influenceId;
private String externalId;
private int totalNumberOfVotes = 0;
private InfluenceAnswer mostVoted;
private MODE currentMode = MODE.text;
private ErrorServerUnknownErrorView communiationError;
private ErrorIllegalDurationNumberView illegalDurationError;
private ErrorNotYetStartedView notStartedView;
private InfoInfluenceAlreadyFinishedView timeoutInfo;
private Date timeout;
private Timer countDownTimer;
private Timer answerRefreshTimer;
public boolean showResults;
// remember the EventListeners we registered to be able to remove them..
private Map<InfluenceAnswerViewInterface<?>, HandlerRegistration> valueChangeHandlerRegistered = new HashMap<InfluenceAnswerViewInterface<?>, HandlerRegistration>();
private Map<InfluenceAnswerViewInterface<?>, HandlerRegistration> formSubmitHandlerRegistered = new HashMap<InfluenceAnswerViewInterface<?>, HandlerRegistration>();
private Map<InfluenceAnswerViewInterface<?>, HandlerRegistration> formSubmitCompleteHandlerRegistered = new HashMap<InfluenceAnswerViewInterface<?>, HandlerRegistration>();
private InfluencePresenter(AppController appController)
{
super(appController);
init();
}
public static InfluencePresenter getInstance(AppController appController)
{
if (instance == null) instance = new InfluencePresenter(appController);
return instance;
}
@Override
public void init()
{
this.view = new InfluenceView(this);
this.setView(view);
this.influenceService = getAppController().getRPCFactory().getInfluenceService();
this.communiationError = new ErrorServerUnknownErrorView();
this.illegalDurationError = new ErrorIllegalDurationNumberView();
this.notStartedView = new ErrorNotYetStartedView();
this.timeoutInfo = new InfoInfluenceAlreadyFinishedView();
this.getAppController().getEventHandler().addHandler(LoginEvent.TYPE, this);
}
@Override
public void go(RootPanel targetPanel)
{
setTargetPanel(targetPanel);
final String influenceId = getAppController().getCurrentHistoryToken().getPresenterModule();
// fade out the header
getAppController().getPageElement(PageElementIDs.teaserImage).hide();
getAppController().getPageElement(PageElementIDs.headerText).setContent("Nimm teil an der Abstimmung und beinflusse das Spiel!");
// fetch the influence with its answers
String sid = getAppController().getLoginManager().getSessionID();
this.influenceService.getInfluence(sid, influenceId, true, new AsyncCallback<Influence>()
{
@Override
public void onFailure(Throwable caught)
{/* show error */
if (caught instanceof NotVisibleException)
InfluencePresenter.this.view.showError(new ErrorVisibilityViolationView());
else if (caught instanceof NullPointerException)
InfluencePresenter.this.view.showError(new ErrorServerUnknownErrorView());
}
@Override
public void onSuccess(Influence result)
{
if (result == null)
onFailure(new NullPointerException("Influence: " + influenceId + " not found."));
else
applyInfluence(result);
}
});
}
protected void applyInfluence(Influence infl)
{
// save essential information
this.influence = infl;
this.influenceId = infl.getId();
this.externalId = infl.getExternalId();
this.minOptions = infl.getMinChoices();
this.maxOptions = infl.getMaxChoices();
this.timeout = infl.getTimeout();
// if is finished, OR not yet started but is admin
this.showResults = determineTimeoutState() > 0 || (determineTimeoutState() < 0 && userIsAdmin());
this.showResults = this.showResults || alreadyVisited(infl);
this.view.showSubmit(!showResults);
if (this.showResults)
{
this.totalNumberOfVotes = infl.getTotalNumberOfGivenVotes();
this.mostVoted = infl.getWinner();
}
this.currentMode = initializeMode(infl.getType());
if (currentMode == null) // if mode is not supported
{
showError(new ErrorCodeUnknownTypeView(infl.getType()));
return;
}
this.setView(view);
// set question and answers information
this.view.setQuestion(infl.getQuestion());
showAnswers(infl);
}
private void showAnswers(Influence influence)
{
addPredefinedAnswers(influence.getPredefinedAnswers());
if (influence.allowFreeAnswers())
{
if (influence.freeAnswersVotable() || showResults || userIsAdmin())
{
addFreeAnswers(influence.getFreeAnswers(), influence.getFreeAnswersVotable());
}
if (!InfluencePresenter.this.showResults) {
//if free answers & not results
scheduleAnswerRefreshmentPolling();
if(isLoggedIn())
addFreeAnswerForm();
}
}
preventNoAnswers(influence);
paintAnswers();
}
private void preventNoAnswers(Influence infl)
{
if (!showResults && !this.isLoggedIn() && infl.allowFreeAnswers() && infl.getPredefinedAnswers().size() == 0
&& (infl.freeAnswersVotable() ? infl.getFreeAnswers().size() == 0 : true))
{
// in case we have nothing to show..
showError(new ErrorLoginNeededView());
}
}
public void paintAnswers()
{
// load answers to view
providePossibleAnswers();
initChangeHandler();
}
public void lazyPaintAdditionalAnswers(List<InfluenceAnswer> newAnswers) {
//paint answers which came from refreshment additionally to the already shown answers which
//should result in NOT touching the other views (especially the already typed content)
boolean votable = influence.freeAnswersVotable();
for(InfluenceAnswer a : newAnswers) {
InfluenceAnswerViewInterface freeAnswerView = strategy.addFreeAnswer(a, votable);
this.view.appendAnswer(freeAnswerView);
}
if (userIsAdmin() || showResults) strategy.appendItemAdministration(getUserId(), userIsAdmin());
strategy.appendItemReporting(influence.getExternalId(), getUserId());
}
public void replaceAnswerViews(InfluenceFreeAnswerViewInterface<AnswerImage> oldAnswerView,
InfluenceAnswerImageView newAnswerView, boolean appendOld, boolean selected) {
this.view.replaceAnswers(oldAnswerView, newAnswerView, appendOld, selected);
}
/**
* shows whether the currently logged in users is attendent of this
* influence or if no user is logged if a correspondent cookie-value can be
* found
*/
private boolean alreadyVisited(Influence influence)
{
if (isLoggedIn())
{
// look for attendees (for multiple users using one pc)
return influence.isAttendee(getUserId());
}
else
{
// otherwise check cookies..
String cookies = Cookies.getCookie(INFLUENCE_COOKIE);
if (cookies == null) return false;
String[] visited = cookies.split(",");
for (String visitedIds : visited)
{
if (visitedIds.equals(String.valueOf(this.influenceId)))
{
return true;
}
}
return false;
}
}
/**
* determine whether the influence is started and if its still running
*
* @return -1 iff not yet started, 0 iff actually runnning, 1 iff in the
* past (timed out)
*/
private byte determineTimeoutState()
{
if (this.timeout == null)
{
return 0;
}
else if (this.timeout.getTime() == 0){
this.view.showError(notStartedView);
return -1;
}
else if (this.timeout.after(new Date()))
{// user still has some time
scheduleCountDownTimer();
// show the form.
return 0;
}
else
{ // time is over. show results and no form.
this.view.showError(timeoutInfo);
return 1;
}
}
private MODE initializeMode(String type)
{
MODE foundMode = MODE.valueOf(type);
if (foundMode == null) return null;
// the not-so-nice determination of the type
switch (foundMode)
{
case text:
strategy = new TextInfluenceStrategy(getAppController(), this);
break;
case image:
strategy = new ImageInfluenceStrategy(getAppController(), this);
this.view.setAnswerColumns(3); // change to three answer in a column for images
break;
case audio:
strategy = new AudioInfluenceStrategy(getAppController(), this);
break;
}
return foundMode;
}
private void addPredefinedAnswers(List<InfluenceAnswer> predefinedAnswers)
{
for (InfluenceAnswer answer : predefinedAnswers)
{
strategy.addPredefinedAnswer(answer);
}
}
private void addFreeAnswers(List<InfluenceAnswer> freeAnswers, boolean votable)
{
for (InfluenceAnswer answer : freeAnswers)
{
strategy.addFreeAnswer(answer, votable);
}
}
private void addFreeAnswerForm()
{
strategy.addFreeAnswerForm();
}
private void providePossibleAnswers()
{
List<InfluenceAnswerViewInterface<Object>> possibleAnswers =
(List<InfluenceAnswerViewInterface<Object>>) strategy.getPossibleAnswers();
if (this.showResults)
{
// FIXME: what to do with deleted answers and their votings? (if set
// to 0, also in administration mode?)
sortResultList(possibleAnswers);
}
else
{
shuffleResultList(possibleAnswers);
}
if (userIsAdmin() || showResults) strategy.appendItemAdministration(getUserId(), userIsAdmin());
strategy.appendItemReporting(influence.getExternalId(), getUserId());
view.setAdministrationVisible(userIsAdmin());
view.setPossibleAnswers(possibleAnswers);
}
private void sortResultList(List<InfluenceAnswerViewInterface<Object>> possibleAnswers)
{
final Map<InfluenceAnswerViewInterface<Object>, InfluenceAnswer> answerMap = this.strategy.getAnswerMap();
Collections.sort(possibleAnswers, new Comparator<InfluenceAnswerViewInterface>()
{
@Override
public int compare(InfluenceAnswerViewInterface o1, InfluenceAnswerViewInterface o2)
{
if (o1 == null || o2 == null || o1.equals(o2) || !answerMap.containsKey(o1)
|| !answerMap.containsKey(o2))
return 0;
else
return answerMap.get(o2).getResult().getVotes() - answerMap.get(o1).getResult().getVotes();
}
});
}
private void shuffleResultList(List<InfluenceAnswerViewInterface<Object>> possibleAnswers)
{
if (possibleAnswers.isEmpty()) return;
InfluenceAnswerViewInterface<Object> freeFormField = possibleAnswers.get(possibleAnswers.size() - 1);
boolean hasFreeFormField = freeFormField instanceof InfluenceFreeAnswerWithFileViewInterface
|| freeFormField instanceof InfluenceFreeAnswerViewInterface;
if (hasFreeFormField) possibleAnswers.remove(freeFormField);
shuffleList(possibleAnswers);
if (hasFreeFormField) possibleAnswers.add(freeFormField);
}
private void shuffleList(List<InfluenceAnswerViewInterface<Object>> list)
{
int n = list.size();
for (int i = 0; i < n; i++)
{
int change = i + Random.nextInt(n - i);
InfluenceAnswerViewInterface<Object> helper = list.get(i);
list.set(i, list.get(change));
list.set(change, helper);
}
}
private void initChangeHandler()
{
List<InfluenceAnswerViewInterface<?>> answerList = getAnswerList();
for (InfluenceAnswerViewInterface<?> a : answerList)
{
if (!this.valueChangeHandlerRegistered.containsKey(a))
{// only register handlers if not already done
this.valueChangeHandlerRegistered.put(a,
a.addValueChangeHandler(this));
}
if (a instanceof InfluenceFreeAnswerViewInterface<?>)
{// this includes both: InfluenceFreeAnswerViews and InfluenceFreeAnswerWithFileViews
if (!this.formSubmitHandlerRegistered.containsKey(a))
{// only register handlers if not already done
this.formSubmitHandlerRegistered.put(a,((InfluenceFreeAnswerViewInterface<?>) a).addFormSubmitHandler(this));
}
if (!this.formSubmitCompleteHandlerRegistered.containsKey(a))
{// only register handlers if not already done
this.formSubmitCompleteHandlerRegistered.put(a,
((InfluenceFreeAnswerViewInterface<?>) a)
.addFormSubmitCompleteHandler(this));
}
}
}
}
private List<InfluenceAnswerViewInterface<?>> getAnswerList()
{
return (List<InfluenceAnswerViewInterface<?>>) strategy.getPossibleAnswers();
}
private void scheduleCountDownTimer()
{
if (countDownTimer != null)
{
countDownTimer.cancel();
}
else
{
countDownTimer = new Timer()
{
public void run()
{
if (InfluencePresenter.this.timeout == null)
return; // not yet started..
Date future = new Date();
future.setTime(future.getTime() + InfluencePresenter.PERIOD_MILLIS_FOR_COUNTDOWN_VISIBLE);
if (InfluencePresenter.this.timeout.after(future))
return;
if (InfluencePresenter.this.timeout.before(new Date()))
{
InfluencePresenter.this.onCountDownTimeout();
return;
}
// show the count down
InfluencePresenter.this.view.showCountdown(InfluencePresenter.this.timeout);
// fetch numbers and percent
// strategy.switchtoResultView(
}
};
}
// Schedule the timer to run every 250ms
countDownTimer.scheduleRepeating(250);
}
private void onCountDownTimeout()
{
this.view.showCountdown(null);
this.view.disableSubmit();
this.countDownTimer.cancel();
InfluencePresenter.this.showResults = true;
refresh();
this.hideErrors();
this.showError(new ErrorNotYetStartedView());
}
@Override
public void onFormValueChangeEvent(FormValueChangeEvent event)
{
InfluenceAnswerViewInterface<String> parent = strategy.findParentViewForElement(event.getSourceWidget());
if (parent == null)
{
return;
}
switch (event.getChangeType())
{
case select:
if (parent.isSelected()) currentlySelectedOptions++;
else currentlySelectedOptions--;
if (currentlySelectedOptions > maxOptions)
{
hideErrors();
showError(new ErrorSelectionRestrictionView(minOptions, maxOptions, currentlySelectedOptions));
enableSubmit(false);
}
else
{
hideErrors();
enableSubmit(true);
}
break;
case message:
// we have a value change..free answer
if (parent instanceof InfluenceFreeAnswerViewInterface)
{
// maybe update the displayed label if desired..
// very costly when used for each character..
strategy.updateFreeAnswerOnChange((InfluenceFreeAnswerViewInterface) parent, event.getValue());
}
break;
case file_drop:
//switch case statement should go now into the file case..
case file:
if (parent instanceof InfluenceFreeAnswerWithFileViewInterface)
{
if (!this.isLoggedIn()) return; // should not be able
String filename = event.getValue();
if (filename == null || filename.isEmpty())
{
Window.alert("Filename is empty or null (InfluencePresenter#623)");
return;
}
if (!this.strategy.hasValidFileEnding(filename))
{
Window.alert("Falscher Dateityp! (InfluencePresenter#628)");
return;
}
String host = GWT.getHostPageBaseURL().replaceAll("web/", "");
// String host = "http://localhost:7999/";
String uploadUrl = host + "servlet/influence/uploadInfluenceData"; // use resource manager
String message = event.getMessage()==null?filename:event.getMessage();
SimpleEntry[] parameter = new SimpleEntry[] {
new SimpleEntry<String, String>("influenceid", this.externalId),
new SimpleEntry<String, String>("message", message),
new SimpleEntry<String, String>("uid", String.valueOf(this.getUserId())),
// FIXME: password not anymore saved on userside, how can we ensure an authentication
// new SimpleEntry<String, String>("secret",this.getAppController().getRequestInformation().getUserSecret())
};
this.strategy.updateFreeAnswerOnChange((InfluenceFreeAnswerViewInterface) parent, message);
((InfluenceFreeAnswerWithFileViewInterface) parent).submitFile(event.getChangeType(), UriUtils.fromSafeConstant(uploadUrl),
parameter);
}
}
}
public void enableSubmit(boolean enable) {
if(enable)
this.view.enableSubmit();
else
this.view.disableSubmit();
}
public void showErrorMinMax(int currentSize)
{
hideErrors();
showError(new ErrorSelectionRestrictionView(minOptions, maxOptions, currentlySelectedOptions));
this.view.disableSubmit();
}
public long getUserId()
{
return getAppController().getRequestInformation().getUserId();
}
public String getUserName()
{
return getAppController().getRequestInformation().getUserName();
}
private boolean isLoggedIn()
{
return getUserId() >= 0;
}
public boolean userIsAdmin()
{
return getAppController().getRequestInformation().getUserIsAdmin();
}
/**
* to be called by View if a submit happens...maybe add lots of parameters
* if Presenter cannot determine himself.
*/
public void onSubmitForm()
{
this.view.hideErrors();
this.view.disableSubmit();
if (this.timeout == null)
{
this.view.showError(new ErrorNotYetStartedView());
return;
}
List<InfluenceAnswerViewInterface<Object>> selected = this.view.getSelectedAnswers();
List<InfluenceAnswer> selectedAnswers = strategy.collectSelectedAnswers(selected);
if (selectedAnswers == null || selectedAnswers.size() == 0) return;
String sid = getAppController().getLoginManager().getSessionID();
getAppController().getRPCFactory().getInfluenceService()
.answerInfluence(sid, this.influenceId, selectedAnswers, new AsyncCallback<Boolean>()
{
@Override
public void onFailure(Throwable caught)
{
Window.alert("Error: " + (caught != null ? caught.getMessage() : "Result was false."));
}
@SuppressWarnings("deprecation")
@Override
public void onSuccess(Boolean result)
{
if (!result)
{
onFailure(null);
return;
}
String infCookies = Cookies.getCookie(INFLUENCE_COOKIE);
Cookies.setCookie(INFLUENCE_COOKIE, (infCookies == null ? "" : infCookies + ",")
+ InfluencePresenter.this.influenceId, new Date(200, 1, 1));
InfluencePresenter.this.showResults = true;
refresh();
}
});
}
private void refresh()
{
refresh(false);
}
private void refresh(boolean log)
{
String sid = getAppController().getLoginManager().getSessionID();
influenceService.getInfluence(sid, this.externalId, log, new AsyncCallback<Influence>()
{
@Override
public void onFailure(Throwable caught)
{
if (caught instanceof NotVisibleException)
InfluencePresenter.this.view.showError(new ErrorVisibilityViolationView());
else if (caught instanceof NullPointerException)
Window.alert("Influence was null");
}
@Override
public void onSuccess(Influence result)
{
if (result == null)
Window.alert("Influence was null");
InfluencePresenter.this.influence = result;
InfluencePresenter.this.strategy.clearAnsweres();
InfluencePresenter.this.hideErrors();
InfluencePresenter.this.currentlySelectedOptions = 0;
InfluencePresenter.this.timeout = result.getTimeout();
// if is finished, OR not yet started but is admin
InfluencePresenter.this.showResults = determineTimeoutState() > 0
|| (determineTimeoutState() < 0 && userIsAdmin());
InfluencePresenter.this.showResults = InfluencePresenter.this.showResults || alreadyVisited(result);
InfluencePresenter.this.view.showSubmit(!showResults);
if (InfluencePresenter.this.showResults)
{
InfluencePresenter.this.totalNumberOfVotes = result.getTotalNumberOfGivenVotes();
InfluencePresenter.this.mostVoted = result.getWinner();
}
showAnswers(result);
}
});
}
private void scheduleAnswerRefreshmentPolling() {
if(answerRefreshTimer != null) {
answerRefreshTimer.cancel();
}
else {
answerRefreshTimer = new Timer()
{
public void run()
{
String sid = getAppController().getLoginManager().getSessionID();
influenceService.getInfluence(sid, InfluencePresenter.this.externalId, new AsyncCallback<Influence>()
{
public void onFailure(Throwable caught) { }
@Override
public void onSuccess(Influence freshInfl) {
List<InfluenceAnswer> newFreeAnswers = compareAnswers(freshInfl, InfluencePresenter.this.influence);
if(newFreeAnswers.size() > 0) {
lazyPaintAdditionalAnswers(newFreeAnswers);
InfluencePresenter.this.influence = freshInfl;
}
}
});
}
private List<InfluenceAnswer> compareAnswers(Influence freshInfl, Influence influence) {
List<InfluenceAnswer> newAnswers = new ArrayList<InfluenceAnswer>();
for(InfluenceAnswer a : freshInfl.getFreeAnswers()) {
if(influence.getFreeAnswer(a.getId()) == null && a.getOwnerId() != getUserId())
{
newAnswers.add(a);
}
}
return newAnswers;
}
};
}
// Schedule the timer to run every 2s
answerRefreshTimer.scheduleRepeating(2000);
}
@Override
public void onFormSubmitCompleteEvent(FormSubmitCompleteEvent event)
{
// only called by events from form options
// of interest if files are completed to be uploaded
InfluenceAnswerViewInterface<?> answer = this.strategy.findParentViewForElement(event.getSourceWidget());
JSONValue result = null;
try
{
result = JSONParser.parseStrict(event.getResult());
}
catch (NullPointerException e)
{
}
catch (JSONException e)
{
result = null;
}
if (result == null || result.isObject() == null)
{
hideErrors();
showError(communiationError);
}
else if (result.isObject().containsKey("success") && result.isObject().get("success").isBoolean() != null
&& result.isObject().get("success").isBoolean().booleanValue()
&& answer instanceof InfluenceFreeAnswerViewInterface && result.isObject().containsKey("message")
&& result.isObject().containsKey("file"))
{
this.strategy.updateFreeAnswerOnUploadSuccess((InfluenceFreeAnswerViewInterface) answer,
event.getSourceParameter(), result);
}
else
{// handle all other errors
JSONObject resultObj = result.isObject();
if (resultObj != null && resultObj.containsKey("error"))
{
hideErrors();
showError(ErrorViewFactory.getErrorView(event.getResult()));
}
}
}
@Override
public void onFormSubmitEvent(FormSubmitEvent event)
{
InfluenceAnswerViewInterface<?> answer = this.strategy.findParentViewForElement(event.getSourceWidget());
// FIXME: is this right?
switch (currentMode)
{
case text: {
this.strategy.updateFreeAnswerOnUploadSuccess((InfluenceFreeAnswerViewInterface) answer, null, null);
break;
}
default:
;
}
}
public int getTotalNumberOfVotes()
{
return this.totalNumberOfVotes;
}
public Object getWinner()
{
return mostVoted;
}
public Influence getInfluenceObject(){
return influence;
}
@Override
public void onLoginSuccessEvent(LoginEvent event)
{
// if(this.view.asWidget().isAttached())
if (externalId != null) // prevent trigger on direct load // TODO RH:
// you could as well just check if presenters
// view is anywhere attached
refresh(true);
}
@Override
public void onLogoutEvent(LogoutEvent event)
{
refresh();
}
@Override
public void onLoginNetworkSuccessEvent(LoginEvent event)
{
refresh(true);
}
@Override
public void onLoginErrorNetworkUserNotFound(LoginErrorNetworkUserNotFoundEvent loginErrorNetworkUserNotFound)
{
}
@Override
public void onLoginErrorWrongUserIDPasswortEvent(
LoginErrorWrongUserIDPasswortEvent loginErrorWrongUserIDPasswortEvent)
{
}
public void hideError(ErrorView errorView)
{
this.view.hideErrors(); // TODO JK: support hiding given error.
}
public void onStartInfluence(Long value)
{
if (value == null) return;
String sid = getAppController().getLoginManager().getSessionID();
getAppController().getRPCFactory().getAdministrationService()
.startInfluence(sid, influenceId, value, new AsyncCallback<Boolean>()
{
@Override
public void onFailure(Throwable caught)
{
view.showError(communiationError);
}
@Override
public void onSuccess(Boolean result)
{
if (!result)
{
onFailure(null);
return;
}
refresh();
}
});
}
public void onStopInfluence()
{
String sid = getAppController().getLoginManager().getSessionID();
getAppController().getRPCFactory().getAdministrationService()
.stopInfluence(sid, influenceId, new AsyncCallback<Boolean>()
{
@Override
public void onFailure(Throwable caught)
{
view.showError(communiationError);
}
@Override
public void onSuccess(Boolean result)
{
if (!result)
{
onFailure(null);
return;
}
refresh();
}
});
}
public void adminIllegalTimeValue(boolean show)
{
if (show) showError(illegalDurationError);
else hideError(illegalDurationError);
}
}