// This file is part of PleoCommand:
// Interactively control Pleo with psychobiological parameters
//
// Copyright (C) 2010 Oliver Hoffmann - Hoffmann_Oliver@gmx.de
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Boston, USA.
package pleocmd.pipe.val;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import pleocmd.exc.InternalException;
import pleocmd.pipe.data.Data;
/**
* Contains one (of possibly more) information from a {@link Data}.<br>
* This class is immutable as long as {@link #set(String)} is not called
* directly from the user.
*
* @author oliver
*/
public abstract class Value {
private ValueType type;
/**
* Creates a new {@link Value}.
*
* @param type
* the type of the new {@link Value}. Must fit to the
* implementing class.
* @see #createForType(ValueType)
*/
protected Value(final ValueType type) {
this.type = type;
}
/**
* @return the {@link ValueType} of this {@link Value}
*/
public final ValueType getType() {
return type;
}
/**
* Changes the {@link ValueType} without changing the value itself.<br>
* Only used during implementations of {@link #compact()}.
*
* @param newType
* new {@link ValueType} - must be compatible with the current
* one !!!
*/
protected final void changeType(final ValueType newType) {
type = newType;
}
// CS_IGNORE_BEGIN This 4 methods need to be overridable
/**
* @return the contents of this {@link Value} as a {@link Long}.
* @throws UnsupportedOperationException
* if this {@link Value} can not be represented as a
* {@link Long}
*/
public long asLong() {
throw new UnsupportedOperationException(
"Cannot convert data's argument to a long integer value");
}
/**
* @return the contents of this {@link Value} as a {@link Double}.
* @throws UnsupportedOperationException
* if this {@link Value} can not be represented as a
* {@link Double}
*/
public double asDouble() {
throw new UnsupportedOperationException(
"Cannot convert data's argument to a double floating point value");
}
/**
* @return the contents of this {@link Value} as a {@link String}.
* @throws UnsupportedOperationException
* if this {@link Value} can not be represented as a
* {@link String}
*/
public String asString() {
throw new UnsupportedOperationException(
"Cannot convert data's argument to a string value");
}
/**
* @return the contents of this {@link Value} as an array of {@link Byte}s.
* @throws UnsupportedOperationException
* if this {@link Value} can not be represented as an array of
* {@link Byte}s
*/
public byte[] asByteArray() {
throw new UnsupportedOperationException(
"Cannot convert data's argument to a byte array value");
}
// CS_IGNORE_END
/**
* Creates a new {@link Value} based on a given {@link ValueType}.
*
* @param type
* {@link ValueType} of the new {@link Value}
* @return new {@link Value}
*/
public static Value createForType(final ValueType type) {
switch (type) {
case Int8:
case Int32:
case Int64:
return new IntValue(type);
case Float32:
case Float64:
return new FloatValue(type);
case UTFString:
case NullTermString:
return new StringValue(type);
case Data:
return new BinaryValue(type);
default:
throw new InternalException(type);
}
}
static ValueType detectFromTypeChar(final char c) {
if (c == IntValue.TYPE_CHAR) return IntValue.RECOMMENDED_TYPE;
if (c == FloatValue.TYPE_CHAR) return FloatValue.RECOMMENDED_TYPE;
if (c == StringValue.TYPE_CHAR) return StringValue.RECOMMENDED_TYPE;
if (c == BinaryValue.TYPE_CHAR) return BinaryValue.RECOMMENDED_TYPE;
return null;
}
static int getAsciiTypeChar(final Value value) {
try {
return (Character) value.getClass().getDeclaredField("TYPE_CHAR")
.get(null);
} catch (final Throwable t) {
// CS_IGNORE_PREV Catch everything that may go wrong here
throw new InternalException("Cannot access field TYPE_CHAR "
+ "of a subclass of Value: %s", t);
}
}
/**
* Should only be called from {@link DataBinaryConverter}.
*
* @param in
* from which to read the {@link Value} in binary form.
* @return number of bytes read from {@link DataInput}
* @throws IOException
* if reading failed
*/
abstract int readFromBinary(final DataInput in) throws IOException;
abstract int writeToBinary(final DataOutput out) throws IOException;
/**
* Should only be called from {@link DataAsciiConverter}.
*
* @param in
* from which to read the {@link Value} in ISO-8859-1 form
* @param len
* the length in bytes of the valid part of "in"
* @throws IOException
* if reading failed
*/
abstract void readFromAscii(final byte[] in, int len) throws IOException;
abstract int writeToAscii(DataOutput out) throws IOException;
@Override
public abstract String toString();
abstract boolean mustWriteAsciiAsHex();
/**
* Must only be used from test cases.
*
* @param content
* the new content
* @return the {@link Value} itself
* @throws IOException
* if the new content is invalid
*/
public abstract Value set(final String content) throws IOException;
@Override
public abstract boolean equals(final Object obj);
@Override
public abstract int hashCode();
public void compact() {
// do nothing
}
}