package com.revolsys.record.query;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.List;
import com.revolsys.datatype.DataType;
import com.revolsys.datatype.DataTypes;
import com.revolsys.identifier.Identifier;
import com.revolsys.identifier.TypedIdentifier;
import com.revolsys.jdbc.field.JdbcFieldDefinition;
import com.revolsys.record.Record;
import com.revolsys.record.code.CodeTable;
import com.revolsys.record.code.CodeTableProperty;
import com.revolsys.record.schema.FieldDefinition;
import com.revolsys.record.schema.RecordDefinition;
import com.revolsys.record.schema.RecordStore;
import com.revolsys.util.Dates;
import com.revolsys.util.Property;
import com.revolsys.util.Strings;
public class Value implements QueryValue {
public static Object getValue(final Object value) {
if (value instanceof TypedIdentifier) {
final Identifier identifier = (Identifier)value;
return identifier;
} else if (value instanceof Identifier) {
final Identifier identifier = (Identifier)value;
return identifier.toSingleValue();
} else {
return value;
}
}
private FieldDefinition fieldDefinition;
private Object displayValue;
private JdbcFieldDefinition jdbcField;
private Object queryValue;
public Value(final FieldDefinition field, final Object value) {
this.fieldDefinition = field;
setQueryValue(value);
this.displayValue = this.queryValue;
setFieldDefinition(field);
}
public Value(final Object value) {
this(JdbcFieldDefinition.newFieldDefinition(value), value);
}
@Override
public void appendDefaultSql(final Query query, final RecordStore recordStore,
final StringBuilder buffer) {
if (this.jdbcField == null) {
buffer.append('?');
} else {
this.jdbcField.addSelectStatementPlaceHolder(buffer);
}
}
@Override
public int appendParameters(final int index, final PreparedStatement statement) {
try {
try {
return this.jdbcField.setPreparedStatementValue(statement, index, this.queryValue);
} catch (final IllegalArgumentException e) {
return this.jdbcField.setPreparedStatementValue(statement, index, null);
}
} catch (final SQLException e) {
throw new RuntimeException("Unable to set value: " + this.queryValue, e);
}
}
@Override
public Value clone() {
try {
return (Value)super.clone();
} catch (final CloneNotSupportedException e) {
return null;
}
}
public void convert(final DataType dataType) {
if (this.queryValue != null) {
final Object value = this.queryValue;
final Object newValue = dataType.toObject(value);
final Class<?> typeClass = dataType.getJavaClass();
if (newValue == null || !typeClass.isAssignableFrom(newValue.getClass())) {
throw new IllegalArgumentException(
"'" + this.queryValue + "' is not a valid " + dataType.getValidationName());
} else {
setQueryValue(newValue);
}
}
}
public void convert(final FieldDefinition field) {
if (field instanceof JdbcFieldDefinition) {
this.jdbcField = (JdbcFieldDefinition)field;
}
convert(field.getDataType());
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof Value) {
final Value value = (Value)obj;
return DataType.equal(value.getValue(), this.getValue());
} else {
return false;
}
}
public Object getDisplayValue() {
return this.displayValue;
}
public JdbcFieldDefinition getJdbcField() {
return this.jdbcField;
}
public Object getQueryValue() {
return this.queryValue;
}
@Override
public String getStringValue(final Record record) {
final Object value = getValue(record);
if (this.fieldDefinition == null) {
return DataTypes.toString(value);
} else {
return this.fieldDefinition.toString(value);
}
}
public Object getValue() {
return this.queryValue;
}
@SuppressWarnings("unchecked")
@Override
public <V> V getValue(final Record record) {
return (V)this.queryValue;
}
@Override
public void setFieldDefinition(final FieldDefinition field) {
if (field != null) {
this.fieldDefinition = field;
if (field instanceof JdbcFieldDefinition) {
this.jdbcField = (JdbcFieldDefinition)field;
} else {
this.jdbcField = JdbcFieldDefinition.newFieldDefinition(this.queryValue);
}
CodeTable codeTable = null;
if (field != null) {
final RecordDefinition recordDefinition = field.getRecordDefinition();
if (recordDefinition != null) {
final String fieldName = field.getName();
codeTable = recordDefinition.getCodeTableByFieldName(fieldName);
if (codeTable instanceof CodeTableProperty) {
final CodeTableProperty codeTableProperty = (CodeTableProperty)codeTable;
if (codeTableProperty.getRecordDefinition() == recordDefinition) {
codeTable = null;
}
}
if (codeTable != null) {
final Identifier id = codeTable.getIdentifier(this.queryValue);
if (id == null) {
this.displayValue = this.queryValue;
} else {
setQueryValue(id);
final List<Object> values = codeTable.getValues(id);
if (values.size() == 1) {
this.displayValue = values.get(0);
} else {
this.displayValue = Strings.toString(":", values);
}
}
}
}
}
}
}
protected void setQueryValue(final Object value) {
this.queryValue = getValue(value);
}
@Override
public void setRecordDefinition(final RecordDefinition recordDefinition) {
final String fieldName = this.fieldDefinition.getName();
if (Property.hasValue(fieldName)) {
final FieldDefinition field = recordDefinition.getField(fieldName);
setFieldDefinition(field);
}
}
public void setValue(Object value) {
value = getValue(value);
if (this.fieldDefinition.getName() == JdbcFieldDefinition.UNKNOWN) {
this.fieldDefinition = JdbcFieldDefinition.newFieldDefinition(value);
}
setQueryValue(value);
}
@Override
public String toFormattedString() {
return toString();
}
@Override
public String toString() {
if (this.displayValue instanceof Number) {
final Object value = this.displayValue;
return DataTypes.toString(value);
} else if (this.displayValue instanceof Date) {
final Date date = (Date)this.displayValue;
final String stringValue = Dates.format("yyyy-MM-dd", date);
return "{d '" + stringValue + "'}";
} else if (this.displayValue instanceof Time) {
final Time time = (Time)this.displayValue;
final String stringValue = Dates.format("HH:mm:ss", time);
return "{t '" + stringValue + "'}";
} else if (this.displayValue instanceof Timestamp) {
final Timestamp time = (Timestamp)this.displayValue;
final String stringValue = Dates.format("yyyy-MM-dd HH:mm:ss.S", time);
return "{ts '" + stringValue + "'}";
} else if (this.displayValue instanceof java.util.Date) {
final java.util.Date time = (java.util.Date)this.displayValue;
final String stringValue = Dates.format("yyyy-MM-dd HH:mm:ss.S", time);
return "{ts '" + stringValue + "'}";
} else {
final Object value = this.displayValue;
final String string = DataTypes.toString(value);
return "'" + string.replaceAll("'", "''") + "'";
}
}
}