package edu.harvard.iq.dataverse.api.dto;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
*
* @author ellenk
*/
public class FieldDTO {
public FieldDTO() {
}
public static FieldDTO createPrimitiveFieldDTO(String typeName, String value) {
FieldDTO primitive = new FieldDTO();
primitive.typeName=typeName;
primitive.setSinglePrimitive(value);
return primitive;
}
public static FieldDTO createMultiplePrimitiveFieldDTO(String typeName, List<String> values) {
FieldDTO primitive = new FieldDTO();
primitive.typeName=typeName;
primitive.setMultiplePrimitive(values);
return primitive;
}
public static FieldDTO createMultipleVocabFieldDTO(String typeName, List<String> values) {
FieldDTO primitive = new FieldDTO();
primitive.typeName=typeName;
primitive.setMultipleVocab(values);
return primitive;
}
public static FieldDTO createVocabFieldDTO(String typeName, String value) {
FieldDTO field = new FieldDTO();
field.typeName=typeName;
field.setSingleVocab(value);
return field;
}
public static FieldDTO createCompoundFieldDTO(String typeName, FieldDTO... value) {
FieldDTO field = new FieldDTO();
field.typeName=typeName;
field.setSingleCompound(value);
return field;
}
/**
* Creates a FieldDTO that contains a size=1 list of compound values
* @param typeName
* @param value
* @return
*/
public static FieldDTO createMultipleCompoundFieldDTO(String typeName, FieldDTO... value) {
FieldDTO field = new FieldDTO();
field.typeName = typeName;
field.setMultipleCompound(value);
return field;
}
public static FieldDTO createMultipleCompoundFieldDTO(String typeName,List<HashSet<FieldDTO>> compoundList) {
FieldDTO field = new FieldDTO();
field.typeName=typeName;
field.setMultipleCompound(compoundList);
return field;
}
String typeName;
Boolean multiple;
String typeClass;
// The contents of value depend on the field attributes
// if single/primitive, value is a String
// if multiple, value is a JSonArray
// multiple/primitive: each JSonArray element will contain String
// multiple/compound: each JSonArray element will contain Set of FieldDTOs
//
JsonElement value;
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public Boolean getMultiple() {
return multiple;
}
public void setMultiple(Boolean multiple) {
this.multiple = multiple;
}
public String getTypeClass() {
return typeClass;
}
public void setTypeClass(String typeClass) {
this.typeClass = typeClass;
}
public String getSinglePrimitive() {
return value==null? "": value.getAsString();
}
String getSingleVocab() {
return value==null? "": value.getAsString();
}
public Set<FieldDTO> getSingleCompound() {
Gson gson = new Gson();
JsonObject elem = (JsonObject) value;
Set<FieldDTO> elemFields = new HashSet<FieldDTO>();
Set<Map.Entry<String, JsonElement>> set = elem.entrySet();
Iterator<Map.Entry<String, JsonElement>> setIter = set.iterator();
while (setIter.hasNext()) {
Map.Entry<String, JsonElement> entry = setIter.next();
FieldDTO field = gson.fromJson(entry.getValue(), FieldDTO.class);
elemFields.add(field);
}
return elemFields;
}
public List<String> getMultiplePrimitive() {
List<String> values = new ArrayList<>();
Iterator<JsonElement> iter = value.getAsJsonArray().iterator();
while (iter.hasNext()) {
values.add(iter.next().getAsString());
}
return values;
}
public List<String> getMultipleVocab() {
List<String> values = new ArrayList<>();
Iterator<JsonElement> iter = value.getAsJsonArray().iterator();
while (iter.hasNext()) {
values.add(iter.next().getAsString());
}
return values;
}
public ArrayList<HashSet<FieldDTO>> getMultipleCompound() {
Gson gson = new Gson();
ArrayList<HashSet<FieldDTO>> fields = new ArrayList<HashSet<FieldDTO>>();
JsonArray array = value.getAsJsonArray();
Iterator<JsonElement> iter = array.iterator();
while (iter.hasNext()) {
JsonObject elem = (JsonObject) iter.next();
HashSet<FieldDTO> elemFields = new HashSet<FieldDTO>();
fields.add(elemFields);
Set<Map.Entry<String, JsonElement>> set = elem.entrySet();
Iterator<Map.Entry<String, JsonElement>> setIter = set.iterator();
while (setIter.hasNext()) {
Map.Entry<String, JsonElement> entry = setIter.next();
FieldDTO field = gson.fromJson(entry.getValue(), FieldDTO.class);
elemFields.add(field);
}
}
return fields;
}
public void setSinglePrimitive(String value) {
Gson gson = new Gson();
typeClass = "primitive";
multiple = false;
this.value = gson.toJsonTree(value, String.class);
}
public void setSingleVocab(String value) {
Gson gson = new Gson();
typeClass = "controlledVocabulary";
multiple = false;
this.value = gson.toJsonTree(value);
}
public void setSingleCompound(FieldDTO... compoundField) {
Gson gson = new Gson();
this.typeClass = "compound";
this.multiple = false;
JsonObject obj = new JsonObject();
for (FieldDTO fieldDTO : compoundField) {
if (fieldDTO!=null) {
obj.add(fieldDTO.typeName,gson.toJsonTree(fieldDTO, FieldDTO.class));
}
}
this.value = obj;
}
public void setMultiplePrimitive(String[] value) {
Gson gson = new Gson();
typeClass = "primitive";
multiple = true;
this.value = gson.toJsonTree(Arrays.asList(value));
}
public void setMultiplePrimitive(List<String> value) {
Gson gson = new Gson();
typeClass = "primitive";
multiple = true;
this.value = gson.toJsonTree(value);
}
public void setMultipleVocab(List<String> value) {
Gson gson = new Gson();
typeClass = "controlledVocabulary";
multiple = true;
this.value = gson.toJsonTree(value);
}
/**
* Set value to a size 1 list of compound fields, that is a single set of primitives
*/
public void setMultipleCompound(FieldDTO... fieldList) {
Gson gson = new Gson();
this.typeClass = "compound";
this.multiple = true;
List<Map<String, FieldDTO>> mapList = new ArrayList<Map<String, FieldDTO>>();
Map<String, FieldDTO> fieldMap = new HashMap<>();
for (FieldDTO fieldDTO : fieldList) {
if (fieldDTO!=null){
fieldMap.put(fieldDTO.typeName, fieldDTO);
}
}
mapList.add(fieldMap);
this.value = gson.toJsonTree(mapList);
}
/**
* Set value to a list of compound fields (each member of the list is a set of fields)
* @param compoundFieldList
*/
public void setMultipleCompound(List<HashSet<FieldDTO>> compoundFieldList) {
Gson gson = new Gson();
this.typeClass = "compound";
this.multiple = true;
List<Map<String, FieldDTO>> mapList = new ArrayList<Map<String, FieldDTO>>();
for (Set<FieldDTO> compoundField : compoundFieldList) {
Map<String, FieldDTO> fieldMap = new HashMap<>();
for (FieldDTO fieldDTO : compoundField) {
fieldMap.put(fieldDTO.typeName, fieldDTO);
}
mapList.add(fieldMap);
}
this.value = gson.toJsonTree(mapList);
}
/**
*
* @return the value of this field, translated from a JsonElement to the
* appropriate DTO format
*/
public Object getConvertedValue() {
if (multiple) {
if (typeClass.equals("compound")) {
return getMultipleCompound();
} else if (typeClass.equals("controlledVocabulary")){
return getMultipleVocab();
} else return getMultiplePrimitive();
} else {
if (typeClass.equals("compound")) {
return getSingleCompound();
} else if (typeClass.equals("controlledVocabulary")){
return getSingleVocab();
} else {
return getSinglePrimitive();
}
}
}
@Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + Objects.hashCode(this.typeName);
hash = 53 * hash + Objects.hashCode(this.multiple);
hash = 53 * hash + Objects.hashCode(this.typeClass);
hash = 53 * hash + Objects.hashCode(this.value);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final FieldDTO other = (FieldDTO) obj;
if (!Objects.equals(this.typeName, other.typeName)) {
return false;
}
if (!Objects.equals(this.multiple, other.multiple)) {
return false;
}
if (!Objects.equals(this.typeClass, other.typeClass)) {
return false;
}
if (!Objects.equals(this.value, other.value)) {
return false;
}
return true;
}
@Override
public String toString() {
return "FieldDTO{" + "typeName=" + typeName + ", multiple=" + multiple + ", typeClass=" + typeClass + ", value=" + getConvertedValue() + '}';
}
}