package org.adaptlab.chpir.android.survey.Rules;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.adaptlab.chpir.android.survey.Models.Instrument;
import org.adaptlab.chpir.android.survey.Models.Rule;
import org.json.JSONException;
import android.util.Log;
/*
* Limit the number of surveys that can be created for a given
* instrument for a given time period. This keeps track of the timestamps
* of each created survey and stores them in the stored params for the
* rule.
*
*/
public class InstrumentSurveyLimitPerMinuteRule extends PassableRule {
private static final String TAG = "InstrumentSurveyLimitPerMinuteRule";
private static final Rule.RuleType RULE_TYPE = Rule.RuleType.INSTRUMENT_SURVEY_LIMIT_PER_MINUTE_RULE;
private static final int MILLISECONDS_IN_MINUTE = 60000;
private SimpleDateFormat mDateFormatter;
private Instrument mInstrument;
private String mFailureMessage;
public InstrumentSurveyLimitPerMinuteRule(Instrument instrument,
String failureMessage) {
mInstrument = instrument;
mFailureMessage = failureMessage;
mDateFormatter = new SimpleDateFormat("EEE MMM dd kk:mm:ss z yyyy"); // The format to use to store timestamps
}
@Override
public boolean passesRule() {
if (getInstrumentRule(mInstrument, RULE_TYPE) == null)
return true;
try {
Rule instrumentRule = getInstrumentRule(mInstrument, RULE_TYPE);
int numberOfSurveys = instrumentRule.getParamJSON().getInt(Rule.NUM_SURVEYS_KEY);
int minuteInterval = instrumentRule.getParamJSON().getInt(Rule.MINUTE_INTERVAL_KEY);
List<Date> surveyTimestamps = parseTimestamps(instrumentRule.<String> getStoredValue(Rule.SURVEY_TIMESTAMPS_KEY));
Date now = new Date();
if (surveyTimestamps.isEmpty()) {
// No surveys yet, add current timestamp and save.
surveyTimestamps = new ArrayList<Date>();
addTimeToTimestamps(surveyTimestamps, instrumentRule, now);
return true;
} else {
// Survey timestamps exist
surveyTimestamps = removeTimestampsOutsideInterval(surveyTimestamps, minuteInterval, now);
if (surveyTimestamps.size() < numberOfSurveys) {
// The current number of timestamps is less than the indicated max.
addTimeToTimestamps(surveyTimestamps, instrumentRule, now);
return true;
} else {
return false;
}
}
} catch (JSONException je) {
Log.e(TAG, "JSON Exception when parsing JSON for rule: " + je);
return false;
} catch (ParseException pe) {
Log.e(TAG, "Parse Exception when parsing JSON for rule stored values: " + pe);
return false;
}
}
@Override
public String getFailureMessage() {
return mFailureMessage;
}
/*
* Convert a serialized list of timestamps to a list of timestamps.
*/
private List<Date> parseTimestamps(String timestamps) throws ParseException {
List<Date> timestampArray = new ArrayList<Date>();
if (timestamps != null) {
for (String dateString : Arrays.asList(timestamps.substring(1,
timestamps.length() - 1).split(", "))) {
timestampArray.add(mDateFormatter.parse(dateString));
}
}
return timestampArray;
}
private void addTimeToTimestamps(List<Date> surveyTimestamps, Rule instrumentRule, Date date) throws ParseException {
surveyTimestamps.add(mDateFormatter.parse(date.toString()));
instrumentRule.setStoredValue(Rule.SURVEY_TIMESTAMPS_KEY, surveyTimestamps);
instrumentRule.save();
}
/*
* Remove all timestamps outside of a given minute interval for a list of dates.
*
* This will remove all timestamps outside of the range referenceTime - minuteInterval.
*
* E.G. if the referenceTime is the current time, and the minute interval is 5, then it will remove
* all timestamps from the list that are older than 5 minutes.
*/
private List<Date> removeTimestampsOutsideInterval(List<Date> surveyTimestamps, int minuteInterval, Date referenceTime) {
List<Date> cleanedTimestamps = new ArrayList<Date>();
Date cutoffTime = new Date(referenceTime.getTime() - (minuteInterval * MILLISECONDS_IN_MINUTE));
for (Date d : surveyTimestamps) {
if (d.after(cutoffTime)) {
cleanedTimestamps.add(d);
}
}
return cleanedTimestamps;
}
}