package net.gcdc.asn1.uper;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.gcdc.asn1.datatypes.IsExtension;
class EnumCoder implements Decoder, Encoder {
@Override public <T> boolean canEncode(T obj, Annotation[] extraAnnotations) {
Class<?> type = obj.getClass();
return type.isEnum();
}
@Override public <T> void encode(BitBuffer bitbuffer, T obj, Annotation[] extraAnnotations) throws Asn1EncodingException {
Class<?> type = obj.getClass();
AnnotationStore annotations = new AnnotationStore(type.getAnnotations(),
extraAnnotations);
UperEncoder.logger.debug("ENUM");
try {
int position = bitbuffer.position();
if (!UperEncoder.hasExtensionMarker(annotations)) {
List<?> values = Arrays.asList(type.getEnumConstants());
int index = values.indexOf(obj);
UperEncoder.logger.debug("enum without ext, index {}, encoding index...", index);
UperEncoder.encodeConstrainedInt(bitbuffer, index, 0, values.size() - 1);
return;
} else {
List<Object> valuesWithinExtensionRoot = new ArrayList<>();
List<Object> valuesOutsideExtensionRoot = new ArrayList<>();
for (Object c : type.getEnumConstants()) {
if (c.getClass().getAnnotation(IsExtension.class) == null) { // double-check
// getClass
valuesWithinExtensionRoot.add(c);
} else {
valuesOutsideExtensionRoot.add(c);
}
}
if (valuesWithinExtensionRoot.contains(obj)) {
bitbuffer.put(false);
int index = valuesWithinExtensionRoot.indexOf(obj);
UperEncoder.encodeConstrainedInt(bitbuffer, index, 0, valuesWithinExtensionRoot.size() - 1);
UperEncoder.logger.debug("ENUM w/ext (index {}), encoded as <{}>", index,
bitbuffer.toBooleanStringFromPosition(position));
return;
} else {
throw new UnsupportedOperationException("Enum extensions are not supported yet");
}
}
} catch (Asn1EncodingException e) {
throw new Asn1EncodingException(type.getName(), e);
}
}
@Override public <T> boolean canDecode(Class<T> classOfT, Annotation[] extraAnnotations) {
return classOfT.isEnum();
}
@Override public <T> T decode(BitBuffer bitbuffer,
Class<T> classOfT,
Annotation[] extraAnnotations) {
AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),
extraAnnotations);
UperEncoder.logger.debug("ENUM");
if (UperEncoder.hasExtensionMarker(annotations)) {
boolean extensionPresent = bitbuffer.get();
UperEncoder.logger.debug("with extension marker, {}", extensionPresent ? "present" : "absent");
if (extensionPresent) {
throw new UnsupportedOperationException(
"choice extension is not implemented yet");
} else {
// We already consumed the bit, keep processing as if there were no extension.
}
}
T[] enumValues = classOfT.getEnumConstants();
int index = (int) UperEncoder.decodeConstrainedInt(bitbuffer,
UperEncoder.newRange(0, enumValues.length - 1, false));
if (index > enumValues.length - 1) { throw new IllegalArgumentException(
"decoded enum index " + index + " is larger then number of elements (0.."
+ enumValues.length + ") in " + classOfT.getName()); }
T value = enumValues[index];
return value; }
}