/*
* Copyright (c) 2017 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.magma.type;
import java.util.ArrayList;
import java.util.Collection;
import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;
import org.obiba.magma.Value;
import org.obiba.magma.ValueConverter;
import org.obiba.magma.ValueLoader;
import org.obiba.magma.ValueSequence;
import org.obiba.magma.ValueType;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
public abstract class AbstractValueType implements ValueType {
private static final long serialVersionUID = -2655334789781837332L;
// private static final Logger log = LoggerFactory.getLogger(AbstractValueType.class);
protected static final char SEPARATOR = ',';
protected static final char QUOTE = '"';
protected final Value nullValue;
protected final ValueSequence nullSequence;
protected AbstractValueType() {
nullValue = Factory.newValue(this, null);
nullSequence = Factory.newSequence(this, null);
}
@Override
public boolean isGeo() {
return false;
}
@Override
public boolean isBinary() {
return false;
}
@NotNull
@Override
public Value nullValue() {
return nullValue;
}
@NotNull
@Override
public ValueSequence nullSequence() {
return nullSequence;
}
@NotNull
@Override
public Value valueOf(@Nullable ValueLoader loader) {
return Factory.newValue(this, loader);
}
@NotNull
@Override
public ValueSequence sequenceOf(@Nullable Iterable<Value> values) {
return Factory.newSequence(this, values);
}
@NotNull
@Override
public ValueSequence sequenceOf(@Nullable String string) {
if(string == null) {
return nullSequence();
}
Collection<Value> values = new ArrayList<>();
StringBuilder currentValue = new StringBuilder();
for(int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
if(c == SEPARATOR) {
values.add(valueOf(currentValue.length() == 0 ? null : currentValue.toString()));
currentValue.setLength(0);
} else {
currentValue.append(c);
}
}
if(currentValue.length() > 0) {
values.add(valueOf(currentValue.toString()));
}
return sequenceOf(values);
}
@NotNull
@SuppressWarnings("IfMayBeConditional")
@Override
public Value convert(@NotNull Value value) {
if(value.getValueType() == this) {
return value;
}
if(value.isNull()) {
return value.isSequence() ? nullSequence() : nullValue();
}
final ValueConverter converter = Factory.converterFor(value.getValueType(), this);
if(value.isSequence()) {
return sequenceOf(
Lists.newArrayList(Iterables.transform(value.asSequence().getValue(), new Function<Value, Value>() {
@Override
public Value apply(Value from) {
return converter.convert(from, AbstractValueType.this);
}
})));
}
return converter.convert(value, this);
}
@Nullable
@Override
public String toString(@Nullable Value value) {
return value == null || value.isNull() //
? null //
: value.isSequence() ? toString(value.asSequence()) : toString(value.getValue());
}
/**
* Allows {@code ValueType} instance to apply formatting or specialised conversion to string representation. For
* example, dates would be formatted in a non-locale dependent way.
*
* @param object a non-null object
* @return a {@code String} representation of the object
*/
@Nullable
protected String toString(@Nullable Object object) {
return object == null ? null : object.toString();
}
/**
* Returns a comma-separated string representation of the sequence. The resulting string can be passed to
* {@code sequenceOf(String)} to obtain the original {@code ValueSequence}.
*
* @param sequence
* @return
*/
@SuppressWarnings("ConstantConditions")
@Nullable
protected String toString(@Nullable ValueSequence sequence) {
if(sequence == null || sequence.isNull()) return null;
StringBuilder sb = new StringBuilder();
for(Value value : sequence.getValue()) {
sb.append(value.isNull() ? "" : escapeAndQuoteIfRequired(value.toString())).append(SEPARATOR);
}
// Remove the last separator
int length = sb.length();
if(length > 0) {
sb.deleteCharAt(length - 1);
}
return sb.toString();
}
@Nullable
protected String escapeAndQuoteIfRequired(@Nullable String value) {
return value;
}
}