package com.revolsys.record.io.format.esri.gdb.xml.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JComponent; import com.revolsys.identifier.Identifier; import com.revolsys.record.code.CodeTable; import com.revolsys.record.io.format.esri.gdb.xml.model.enums.FieldType; import com.revolsys.record.io.format.esri.gdb.xml.model.enums.MergePolicyType; import com.revolsys.record.io.format.esri.gdb.xml.model.enums.SplitPolicyType; import com.revolsys.util.CompareUtil; public class Domain implements CodeTable, Cloneable { private List<CodedValue> codedValues = new ArrayList<>(); private Map<Identifier, List<Object>> idValueMap = new HashMap<>(); private int maxId = 0; private Map<String, Identifier> stringIdMap = new HashMap<>(); private JComponent swingEditor; private Map<String, Identifier> valueIdMap = new HashMap<>(); private String description; private String domainName; private FieldType fieldType = FieldType.esriFieldTypeSmallInteger; private MergePolicyType mergePolicy = MergePolicyType.esriMPTAreaWeighted; private String owner; private SplitPolicyType splitPolicy = SplitPolicyType.esriSPTDuplicate; public Domain() { } public Domain(final String domainName, final FieldType fieldType, final String description) { this.domainName = domainName; this.fieldType = fieldType; this.description = description; } public synchronized Domain addCodedValue(final Object code, final String name) { final Identifier identifier = Identifier.newIdentifier(code); final CodedValue value = new CodedValue(code, name); this.codedValues.add(value); final List<Object> values = Collections.<Object> singletonList(name); this.idValueMap.put(identifier, values); this.stringIdMap.put(code.toString(), identifier); this.valueIdMap.put(name.toLowerCase(), identifier); if (code instanceof Number) { final int id = ((Number)code).intValue(); if (this.maxId < id) { this.maxId = id; } } return this; } public synchronized Domain addCodedValue(final String name) { newCodedValue(name); return this; } @Override public Domain clone() { try { final Domain clone = (Domain)super.clone(); clone.idValueMap = new HashMap<>(); clone.stringIdMap = new HashMap<>(); clone.valueIdMap = new HashMap<>(); clone.codedValues = new ArrayList<>(); for (final CodedValue codedValue : this.codedValues) { clone.addCodedValue(codedValue.getCode(), codedValue.getName()); } return clone; } catch (final CloneNotSupportedException e) { throw new RuntimeException(e); } } @Override public int compare(final Object value1, final Object value2) { if (value1 == null) { if (value2 == null) { return 0; } else { return 1; } } else if (value2 == null) { return -1; } else { final Object codeValue1 = getValue(Identifier.newIdentifier(value1)); final Object codeValue2 = getValue(Identifier.newIdentifier(value2)); return CompareUtil.compare(codeValue1, codeValue2); } } public List<CodedValue> getCodedValues() { return this.codedValues; } @Override public Map<Identifier, List<Object>> getCodes() { return Collections.unmodifiableMap(this.idValueMap); } public String getDescription() { return this.description; } public String getDomainName() { return this.domainName; } @Override public List<String> getFieldNameAliases() { return Collections.emptyList(); } public FieldType getFieldType() { return this.fieldType; } @Override public Identifier getIdentifier(final List<Object> values, final boolean loadMissing) { if (values.size() == 1) { final Object value = values.get(0); if (value == null) { return null; } else if (this.idValueMap.containsKey(value)) { return Identifier.newIdentifier(value); } else if (this.stringIdMap.containsKey(value.toString())) { return this.stringIdMap.get(value.toString()); } else { final String lowerValue = ((String)value).toLowerCase(); final Identifier id = this.valueIdMap.get(lowerValue); return id; } } else { throw new IllegalArgumentException("Expecting only a single value " + values); } } @Override public Identifier getIdentifier(final Map<String, ? extends Object> values) { final Object name = getName(values); return getIdentifier(name); } @Override public List<Identifier> getIdentifiers() { return new ArrayList<>(this.idValueMap.keySet()); } @Override public String getIdFieldName() { return getDomainName() + "_ID"; } @Override public Map<String, ? extends Object> getMap(final Identifier id) { final Object value = getValue(id); return Collections.singletonMap("NAME", value); } public MergePolicyType getMergePolicy() { return this.mergePolicy; } @Override public String getName() { return getDomainName(); } public String getName(final Map<String, ? extends Object> values) { return (String)values.get("NAME"); } public String getOwner() { return this.owner; } public SplitPolicyType getSplitPolicy() { return this.splitPolicy; } @Override public JComponent getSwingEditor() { return this.swingEditor; } @Override @SuppressWarnings("unchecked") public <V> V getValue(final Identifier id) { final List<Object> values = getValues(id); if (values == null) { return null; } else { final Object value = values.get(0); return (V)value; } } @Override public <V> V getValue(final Object id) { return getValue(Identifier.newIdentifier(id)); } @Override public List<String> getValueFieldNames() { return Arrays.asList("NAME"); } @Override public List<Object> getValues(final Identifier id) { if (id == null) { return null; } else { List<Object> values = this.idValueMap.get(id); if (values == null) { final Identifier objectId = this.stringIdMap.get(id.toString()); if (objectId == null) { return null; } else { values = this.idValueMap.get(objectId); } } return Collections.unmodifiableList(values); } } @Override public boolean isEmpty() { return this.idValueMap.isEmpty(); } @Override public boolean isLoaded() { return true; } @Override public boolean isLoading() { return false; } public synchronized Identifier newCodedValue(final String name) { Object id; switch (getFieldType()) { case esriFieldTypeInteger: id = (int)++this.maxId; break; case esriFieldTypeSmallInteger: id = (short)++this.maxId; break; default: throw new RuntimeException("Cannot generate code for field type " + getFieldType()); } addCodedValue(id, name); return Identifier.newIdentifier(id); } @Override public void refresh() { } public synchronized void setCodedValues(final List<CodedValue> codedValues) { this.codedValues = new ArrayList<>(); for (final CodedValue codedValue : codedValues) { final Object code = codedValue.getCode(); final String name = codedValue.getName(); addCodedValue(code, name); } } public void setDescription(final String description) { this.description = description; } public void setDomainName(final String domainName) { this.domainName = domainName; } public void setFieldType(final FieldType fieldType) { this.fieldType = fieldType; } public void setMergePolicy(final MergePolicyType mergePolicy) { this.mergePolicy = mergePolicy; } public void setOwner(final String owner) { this.owner = owner; } public void setSplitPolicy(final SplitPolicyType splitPolicy) { this.splitPolicy = splitPolicy; } public void setSwingEditor(final JComponent swingEditor) { this.swingEditor = swingEditor; } @Override public String toString() { return this.domainName; } }