/*
* Copyright (C) 2013 lichtflut Forschungs- und Entwicklungsgesellschaft mbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.arastreju.sge.model.nodes;
import de.lichtflut.infra.Infra;
import org.arastreju.sge.model.ElementaryDataType;
import org.arastreju.sge.model.nodes.views.SNScalar;
import org.arastreju.sge.model.nodes.views.SNText;
import org.arastreju.sge.model.nodes.views.SNTimeSpec;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* <p>
* Base for data nodes. Data nodes may have no outgoing associations
* but may only be associated from resource nodes.
* </p>
*
* <p>
* Created: 16.01.2009
* </p>
*
* @author Oliver Tigges
*/
public class SNValue implements ValueNode, Serializable {
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
private final ElementaryDataType datatype;
private final Object value;
private final Locale locale;
// -----------------------------------------------------
/**
* Constructor.
* @param datatype The datatype.
* @param value The value.
*/
public SNValue(final ElementaryDataType datatype, final Object value) {
this(datatype, value, null);
}
/**
* Constructor.
* @param datatype The datatype.
* @param value The value.
* @param locale The locale
*/
public SNValue(final ElementaryDataType datatype, final Object value, final Locale locale) {
if (value == null) {
throw new IllegalArgumentException("Value may not be null");
}
this.datatype = datatype;
this.locale = locale;
try {
this.value = convert(value, datatype);
} catch (ParseException e) {
throw new IllegalStateException("Value not of expected type", e);
}
}
//-----------------------------------------------------
public Object getValue(){
switch (datatype) {
case BOOLEAN:
return getBooleanValue();
case URI:
case STRING:
return getStringValue();
case DECIMAL:
return getDecimalValue();
case INTEGER:
return getIntegerValue();
case DATE:
case TIME_OF_DAY:
case TIMESTAMP:
return getTimeValue();
default:
throw new IllegalStateException("Cannot determine type of value: " + value + " (" + datatype + ")");
}
}
public Locale getLocale() {
return locale;
}
public ElementaryDataType getDataType() {
return datatype;
}
// ----------------------------------------------------
public boolean isResourceNode() {
return false;
}
public boolean isValueNode() {
return true;
}
public ResourceNode asResource() {
throw new IllegalStateException("Not a resource: " + this);
}
public ValueNode asValue() {
return this;
}
// ------------------------------------------------------
public String getStringValue() {
if (value == null){
return "";
}
switch (datatype) {
case DATE:
case TIME_OF_DAY:
case TIMESTAMP:
return DATE_FORMAT.format(getTimeValue());
case BOOLEAN:
return value.toString();
default:
return value.toString();
}
}
public BigDecimal getDecimalValue() {
if (value instanceof String){
return new BigDecimal((String) value);
}
return (BigDecimal) value;
}
public BigInteger getIntegerValue() {
if (value instanceof BigInteger) {
return (BigInteger) value;
}
if (value instanceof String){
return new BigInteger((String) value);
}
if (value instanceof Number) {
Number number = (Number) value;
return BigInteger.valueOf(number.longValue());
}
throw new IllegalStateException("Cannot convert '" + value + "' to an BigInteger.");
}
public Date getTimeValue() {
return (Date) value;
}
public Boolean getBooleanValue() {
return (Boolean) value;
}
// -----------------------------------------------------
public SNTimeSpec asTimeSpec() {
return new SNTimeSpec(this);
}
public SNScalar asScalar() {
return new SNScalar(this);
}
public SNText asText() {
return new SNText(this);
}
// -----------------------------------------------------
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(getStringValue());
if (locale != null) {
sb.append(" [").append(locale).append("]");
}
return sb.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((datatype == null) ? 0 : datatype.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (obj instanceof ValueNode) {
ValueNode other = (ValueNode) obj;
if (!Infra.equals(value, other.getValue())) {
return false;
}
if (!Infra.equals(datatype, other.getDataType())) {
return false;
}
if (!Infra.equals(locale, other.getLocale())) {
return false;
}
return true;
}
return super.equals(obj);
}
// -----------------------------------------------------
public int compareTo(final ValueNode other) {
switch (datatype) {
case BOOLEAN:
return getBooleanValue().compareTo(other.getBooleanValue());
case URI:
case STRING:
return getStringValue().compareTo(other.getStringValue());
case DECIMAL:
return getDecimalValue().compareTo(other.getDecimalValue());
case INTEGER:
return getIntegerValue().compareTo(other.getIntegerValue());
case DATE:
case TIME_OF_DAY:
case TIMESTAMP:
return getTimeValue().compareTo(other.getTimeValue());
default:
throw new IllegalStateException("Cannot determine type of value: " + value + " (" + datatype + ")");
}
}
// -- CONVERSIONS -------------------------------------
/**
* Converts a String value to needed type, if necessary.
* @throws ParseException
*/
private Object convert(final Object value, final ElementaryDataType datatype) throws ParseException {
if (value instanceof String) {
return convertString((String) value, datatype);
}
return value;
}
private Object convertString(final String value, final ElementaryDataType datatype) throws ParseException {
switch (datatype) {
case DATE:
case TIME_OF_DAY:
case TIMESTAMP:
return DATE_FORMAT.parse(value);
case BOOLEAN:
return Boolean.parseBoolean(value);
case DECIMAL:
return new BigDecimal(value);
case INTEGER:
return new BigInteger(value);
case URI:
case STRING:
case PROPER_NAME:
case TERM:
case UNDEFINED:
return value;
case RESOURCE:
throw new IllegalStateException("SNValue may not contain a value of type RESOURCE.");
default:
throw new IllegalStateException("Unsupported datatype: " + datatype);
}
}
}