/*
* Copyright (C) 2010-2016 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo FLOW.
*
* Akvo FLOW is free software: you can redistribute it and modify it under the terms of
* the GNU Affero General Public License (AGPL) as published by the Free Software Foundation,
* either version 3 of the License or any later version.
*
* Akvo FLOW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License included below for more details.
*
* The full license text can also be seen at <http://www.gnu.org/licenses/agpl.html>.
*/
package com.gallatinsystems.surveyal.domain;
import static com.gallatinsystems.common.Constants.MAX_LENGTH;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.PersistenceCapable;
import org.waterforpeople.mapping.domain.QuestionAnswerStore;
import com.gallatinsystems.framework.domain.BaseDomain;
import com.gallatinsystems.survey.domain.Question;
/**
* Domain structure to represent a location about which there is data gathered through one or more
* surveys. The sublevel1-6 fields are geographical subdivisions (state/province/sector/cell, etc)
* where the exact definition of what each level corresponds to depends on the country in which the
* point is located. Details about SurveyedLocales are stored using SurveyalValue which has a loose
* association with this object.
*
* @author Christopher Fagiani
*/
@PersistenceCapable
public class SurveyedLocale extends BaseDomain {
private static final long serialVersionUID = -7908506708459480822L;
/**
* The pattern of the base32 surveyed locale id generated by the function generateBase32Uuid()
*/
public static final String IDENTIFIER_PATTERN = "^[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}$";
private String organization;
private String systemIdentifier;
private String identifier;
private String displayName;
private String countryCode;
private String sublevel1;
private String sublevel2;
private String sublevel3;
private String sublevel4;
private String sublevel5;
private String sublevel6;
private Set<Long> surveyInstanceContrib;
private List<String> geocells;
private String localeType;
private Double latitude;
private Double longitude;
private boolean ambiguous;
private String currentStatus;
private Long surveyGroupId;
private Date lastSurveyedDate;
private Long lastSurveyalInstanceId;
private Long creationSurveyId;
@NotPersistent
private List<SurveyalValue> surveyalValues;
public Long getLastSurveyalInstanceId() {
return lastSurveyalInstanceId;
}
public void setLastSurveyalInstanceId(Long lastSurveyalInstanceId) {
this.lastSurveyalInstanceId = lastSurveyalInstanceId;
}
public SurveyedLocale() {
ambiguous = false;
}
public Date getLastSurveyedDate() {
return lastSurveyedDate;
}
public void setLastSurveyedDate(Date lastSurveyedDate) {
this.lastSurveyedDate = lastSurveyedDate;
}
public boolean isAmbiguous() {
return ambiguous;
}
public void setAmbiguous(boolean ambiguous) {
this.ambiguous = ambiguous;
}
public String getOrganization() {
return organization;
}
public void setOrganization(String organization) {
this.organization = organization;
}
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getSublevel1() {
return sublevel1;
}
public void setSublevel1(String sublevel1) {
this.sublevel1 = sublevel1;
}
public String getSublevel2() {
return sublevel2;
}
public void setSublevel2(String sublevel2) {
this.sublevel2 = sublevel2;
}
public String getSublevel3() {
return sublevel3;
}
public void setSublevel3(String sublevel3) {
this.sublevel3 = sublevel3;
}
public String getSublevel4() {
return sublevel4;
}
public void setSublevel4(String sublevel4) {
this.sublevel4 = sublevel4;
}
public String getSublevel5() {
return sublevel5;
}
public void setSublevel5(String sublevel5) {
this.sublevel5 = sublevel5;
}
public String getSublevel6() {
return sublevel6;
}
public void setSublevel6(String sublevel6) {
this.sublevel6 = sublevel6;
}
public String getLocaleType() {
return localeType;
}
public void setLocaleType(String localeType) {
this.localeType = localeType;
}
public Double getLatitude() {
return latitude;
}
public void setLatitude(Double latitude) {
this.latitude = latitude;
}
public Double getLongitude() {
return longitude;
}
public void setLongitude(Double longitude) {
this.longitude = longitude;
}
public String getSystemIdentifier() {
return systemIdentifier;
}
public void setSystemIdentifier(String systemIdentifier) {
this.systemIdentifier = systemIdentifier;
}
public List<SurveyalValue> getSurveyalValues() {
return surveyalValues;
}
public void setSurveyalValues(List<SurveyalValue> surveyalValues) {
this.surveyalValues = surveyalValues;
}
public void setCurrentStatus(String currentStatus) {
this.currentStatus = currentStatus;
}
public Long getSurveyGroupId() {
return surveyGroupId;
}
public void setSurveyGroupId(Long surveyGroupId) {
this.surveyGroupId = surveyGroupId;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName.length() > MAX_LENGTH ? displayName.substring(0, MAX_LENGTH)
.trim() : displayName;
}
public Set<Long> getSurveyInstanceContrib() {
return surveyInstanceContrib;
}
public void addContributingSurveyInstance(Long surveyInstanceId) {
if (surveyInstanceContrib == null) {
surveyInstanceContrib = new HashSet<Long>();
}
surveyInstanceContrib.add(surveyInstanceId);
}
public void setSurveyInstanceContrib(Set<Long> surveyInstanceIdList) {
this.surveyInstanceContrib.addAll(surveyInstanceIdList);
}
public String getCurrentStatus() {
return currentStatus;
}
public List<String> getGeocells() {
return geocells;
}
public void setGeocells(List<String> geocells) {
this.geocells = geocells;
}
public Long getCreationSurveyId() {
return creationSurveyId;
}
public void setCreationSurveyId(Long creationSurveyId) {
this.creationSurveyId = creationSurveyId;
}
/**
* Given a list of datapoint name questions, and the list of responses for
* this locale's registration form, reassemble the display name
*/
public void assembleDisplayName(List<Question> nameQuestions, List<QuestionAnswerStore> responses) {
// Map question id to value responses (faster lookups for each question id)
Map<Long, String> nameResponses = new HashMap<>();
for (QuestionAnswerStore qas : responses) {
Long qId = qas.getQuestionIDLong();
if (qId != null && qas.getValue() != null) {
nameResponses.put(qId, qas.getDatapointNameValue());
}
}
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Question q : nameQuestions) {
Long id = q.getKey().getId();
if (!nameResponses.containsKey(id)) {
continue;
}
if (!first) {
sb.append(" - ");
}
sb.append(nameResponses.get(id));
first = false;
}
displayName = sb.toString();
}
/**
* Creates a base32 version of a UUID. In the output, it replaces the following letters: l, o, i
* are replace by w, x, y, to avoid confusion with 1 and 0 we don't use the z as it can easily
* be confused with 2, especially in handwriting. If we can't form the base32 version, we return
* an empty string. The same code is used in the FLOW Mobile app:
* https://github.com/akvo/akvo-flow-mobile/blob/feature/pointupdates/survey/
* src/com/gallatinsystems/survey/device/util/Base32.java The resulting identifier is a string
* in the format xxxx-xxxx-xxxx
*
* @return
*/
public static String generateBase32Uuid() {
final String uuid = UUID.randomUUID().toString();
String strippedUUID = (uuid.substring(0, 13) + uuid.substring(24, 27)).replace("-", "");
String result = null;
try {
Long id = Long.parseLong(strippedUUID, 16);
result = Long.toString(id, 32).replace("l", "w").replace("o", "x").replace("i", "y");
} catch (NumberFormatException e) {
// if we can't create the base32 UUID string, return the original uuid.
result = uuid;
}
// insert dashes for readability
return String.format("%s-%s-%s", result.substring(0, 4), result.substring(4, 8),
result.substring(8));
}
/**
* Creates a base32 version of a UUID, starting with the old style identifiers for
* surveyedLocales as a seed. The resulting identifier is a string in the format xxxx-xxxx-xxxx
*
* @param oldStyleIdentifier
* @return
*/
public static String generateBase32Uuid(String oldStyleIdentifier) {
String base32Uuid = SurveyedLocale.generateBase32Uuid();
if (oldStyleIdentifier.length() < 8) {
return base32Uuid;
}
return String.format("%s-%s-%s", oldStyleIdentifier.substring(0, 4),
oldStyleIdentifier.substring(4, 8),
base32Uuid.substring(10));
}
}