package org.activityinfo.model.type; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.activityinfo.model.form.FormClass; import org.activityinfo.model.resource.Record; import org.activityinfo.model.resource.ResourceId; import org.activityinfo.model.resource.ResourceIdPrefixType; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; /** * A type that represents a link or reference to another {@code Resource} */ public class ReferenceType implements ParametrizedFieldType { public static class TypeClass implements ParametrizedFieldTypeClass, RecordFieldTypeClass { private TypeClass() { } @Override public String getId() { return "REFERENCE"; } @Override public FieldType createType() { return new ReferenceType() .setCardinality(Cardinality.SINGLE) .setRange(Collections.<ResourceId>emptySet()); } @Override public FieldType deserializeType(Record parameters) { ReferenceType type = new ReferenceType(); type.setCardinality(Cardinality.valueOf(parameters.getString("cardinality"))); type.setRange(parameters.getStringList("range")); return type; } @Override public FieldValue deserialize(Record record) { return ReferenceValue.fromRecord(record); } @Override public FormClass getParameterFormClass() { FormClass formClass = new FormClass(ResourceIdPrefixType.TYPE.id("ref")); return formClass; } }; public static final TypeClass TYPE_CLASS = new TypeClass(); private Cardinality cardinality; private Set<ResourceId> range; public ReferenceType() { } @Override public ParametrizedFieldTypeClass getTypeClass() { return TYPE_CLASS; } public Cardinality getCardinality() { return cardinality; } public ReferenceType setCardinality(Cardinality cardinality) { this.cardinality = cardinality; return this; } /** * @return the set of FormClasses to which fields of this type can refer. */ public Set<ResourceId> getRange() { return range; } public void setRange(ResourceId formClassId) { this.range = Collections.singleton(formClassId); } private void setRange(List<String> range) { Set<ResourceId> formClassIds = Sets.newHashSet(); for(String id : range) { formClassIds.add(ResourceId.valueOf(id)); } setRange(formClassIds); } public ReferenceType setRange(Set<ResourceId> range) { this.range = range; return this; } @Override public Record getParameters() { return new Record() .set("classId", getTypeClass().getParameterFormClass().getId()) .set("range", toArray(range)) .set("cardinality", cardinality); } @Override public boolean isValid() { return true; } private List<String> toArray(Set<ResourceId> range) { List<String> ids = Lists.newArrayList(); for(ResourceId id : range) { ids.add(id.asString()); } return ids; } /** * Convenience constructor for ReferenceTypes with single cardinality * @param formClassId the id of the form class which is the range of this field * @return a new ReferenceType */ public static ReferenceType single(ResourceId formClassId) { ReferenceType type = new ReferenceType(); type.setCardinality(Cardinality.SINGLE); type.setRange(Collections.singleton(formClassId)); return type; } /** * Convenience constructor for ReferenceTypes with single cardinality * @param formClassIds the ids of the form class which constitute the range of this field * @return a new ReferenceType */ public static ReferenceType single(Iterable<ResourceId> formClassIds) { ReferenceType type = new ReferenceType(); type.setCardinality(Cardinality.SINGLE); type.setRange(Sets.newHashSet(formClassIds)); return type; } public static FieldType multiple(Collection<ResourceId> formClassIds) { ReferenceType type = new ReferenceType(); type.setCardinality(Cardinality.MULTIPLE); type.setRange(Sets.newHashSet(formClassIds)); return type; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } ReferenceType that = (ReferenceType) o; if (cardinality != that.cardinality) { return false; } if (!range.equals(that.range)) { return false; } return true; } @Override public int hashCode() { int result = cardinality.hashCode(); result = 31 * result + range.hashCode(); return result; } @Override public String toString() { return "ReferenceType{" + "cardinality=" + cardinality + ", range=" + range + '}'; } }