package edu.colostate.vchill.socket;
import edu.colostate.vchill.ChillDefines;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* CHILL socket protocol response packet
*
* @author Jochen Deyke
* @author jpont
* @version 2009-03-06
*/
public final class SocketResponse {
public static final int BYTE_SIZE = ChillDefines.INT_BYTE_SIZE * 7;
/**
* status codes
*/
public enum Status {
/**
* not used *
*/
unknown,
/**
* error opening file or directory
*/
OPEN_ERROR,
/**
* sweep number out of range
*/
POSITION_ERROR,
/**
* not used by Java VCHILL *
*/
BLOCKLIM,
END_VOLUME,
END_SWEEP,
END_FILE,
/**
* sent immediately after the listing of files/directories/bookmarks
*/
DIRECTORY_SENT,
FORMAT_ERROR,
NO_SWEEPS,
RAY_READ,
STATUS_UPDATE,
STOPPED,
/**
* reserved for bit running message; not used
*/
running,
/**
* There will be a (text) listing of files/directories/bookmarks of length <code>extStatus</code> bytes immediately following this header
*/
DIRECTORY_FOLLOWS,
SERVER_BUSY,
SERVER_READY,
SERVER_TIMEOUT,
/**
* malformed/unclear request
*/
REQUEST_ERROR,
/**
* bad username/signon
*/
SIGNON_UNKNOWN,
/**
* bad password
*/
PASSWD_FAIL,
/**
* There will be a (text) message of length <code>extStatus</code> bytes immediately following this header
*/
MESSAGE_FOLLOWS,
SERVER_FAILURE,
/**
* placeholder; not yet used *
*/
UnknownStatus23,
/**
* placeholder; not yet used *
*/
UnknownStatus24,
/**
* placeholder; not yet used *
*/
UnknownStatus25,
/**
* placeholder; not yet used *
*/
UnknownStatus26,
/**
* placeholder; not yet used *
*/
UnknownStatus27,
}
/* ARCH_RUNNING is a status bit which is or'd with other condition codes */
public static final int ARCH_RUNNING = 256;
/* ARCH_CAL_FILE is a status bit which is or'd with other condition codes */
public static final int ARCH_CAL_FILE = 512;
/**
* result code
*/
private final Status status;
private final boolean running;
private final boolean calibrationPresent;
/**
* additional status or number of additional bytes
*/
private final int extStatus;
/**
* current data position: volume #
*/
private final int vol;
/**
* current data position: sweep #
*/
private final int sweep;
/**
* current data position: ray #
*/
private final int ray;
/**
* current scan mode
*/
private final int scanMode;
/**
* max number of sweeps this volume
*/
private final int maxSweeps;
/**
* @param in the DataInput to load values from
*/
public SocketResponse(final DataInput in) throws IOException {
int tmp = in.readInt();
this.running = (tmp & ARCH_RUNNING) != 0;
this.calibrationPresent = (tmp & ARCH_CAL_FILE) != 0;
this.status = Status.values()[tmp & (ARCH_RUNNING - 1)]; //&0xff
this.extStatus = in.readInt();
this.vol = in.readInt();
this.sweep = in.readInt();
this.ray = in.readInt();
this.scanMode = in.readInt();
this.maxSweeps = in.readInt();
}
/**
* @param data the byte[] to load values from
* @param offset the index of the first byte to read
*/
public SocketResponse(final byte[] data, int offset) {
if (data.length < offset + SocketResponse.BYTE_SIZE - 1) {
throw new IllegalArgumentException("not enough data in input array");
}
int tmp = SocketUtil.readInt(data, offset);
offset += ChillDefines.INT_BYTE_SIZE;
this.running = (tmp & ARCH_RUNNING) != 0;
this.calibrationPresent = (tmp & ARCH_CAL_FILE) != 0;
this.status = Status.values()[tmp & (ARCH_RUNNING - 1)];
this.extStatus = SocketUtil.readInt(data, offset);
offset += ChillDefines.INT_BYTE_SIZE;
this.vol = SocketUtil.readInt(data, offset);
offset += ChillDefines.INT_BYTE_SIZE;
this.sweep = SocketUtil.readInt(data, offset);
offset += ChillDefines.INT_BYTE_SIZE;
this.ray = SocketUtil.readInt(data, offset);
offset += ChillDefines.INT_BYTE_SIZE;
this.scanMode = SocketUtil.readInt(data, offset);
offset += ChillDefines.INT_BYTE_SIZE;
this.maxSweeps = SocketUtil.readInt(data, offset);
offset += ChillDefines.INT_BYTE_SIZE;
assert offset == SocketResponse.BYTE_SIZE : "number of bytes read != size";
}
/**
* Assumes an offset of 0.
*
* @param data the byte[] to load values from
*/
public SocketResponse(final byte[] data) {
this(data, 0);
}
/**
* Assumes an offset of 0 and a new/uninitialized byte[].
*/
public SocketResponse() {
this(new byte[BYTE_SIZE]);
}
/**
* @param out the DataOutput to write values to
*/
public void write(final DataOutput out) {
try {
int tmp = this.status.ordinal();
if (this.running) tmp |= ARCH_RUNNING;
if (this.calibrationPresent) tmp |= ARCH_CAL_FILE;
out.writeInt(tmp);
out.writeInt(this.extStatus);
out.writeInt(this.vol);
out.writeInt(this.sweep);
out.writeInt(this.ray);
out.writeInt(this.scanMode);
out.writeInt(this.maxSweeps);
} catch (IOException ioe) {
throw new Error(ioe);
}
}
/**
* Translates this SocketResponse object to a byte[] for transmission over the network
*
* @return byte[] representation of this SocketResponse object
*/
public byte[] getBytes() {
final byte[] output = new byte[SocketResponse.BYTE_SIZE];
int offset = 0;
int tmp = this.status.ordinal();
if (running) tmp |= ARCH_RUNNING;
if (calibrationPresent) tmp |= ARCH_CAL_FILE;
offset += SocketUtil.writeInt(tmp, output, offset);
offset += SocketUtil.writeInt(this.extStatus, output, offset);
offset += SocketUtil.writeInt(this.vol, output, offset);
offset += SocketUtil.writeInt(this.sweep, output, offset);
offset += SocketUtil.writeInt(this.ray, output, offset);
offset += SocketUtil.writeInt(this.scanMode, output, offset);
offset += SocketUtil.writeInt(this.maxSweeps, output, offset);
assert offset == SocketResponse.BYTE_SIZE : "Num bytes returned != size";
return output;
}
public String toString() {
return this.getStatusString() +
"Ext status: " + this.extStatus + "\n" +
"Volume number: " + this.vol + "\n" +
"Sweep number: " + this.sweep + "\n" +
"Ray number: " + this.ray + "\n" +
"Scan mode: " + this.scanMode + "\n" +
"Max sweeps this vol: " + this.maxSweeps;
}
public Status getStatus() {
return this.status;
}
public boolean isRunning() {
return this.running;
}
public boolean isCalibrationPresent() {
return this.calibrationPresent;
}
//public boolean isArchiveRunning () { return this.running; }
public int getExtStatus() {
return this.extStatus;
}
public int getMaxSweeps() {
return this.maxSweeps;
}
public int getRayNumber() {
return this.ray;
}
private String getStatusString() {
StringBuilder result = new StringBuilder();
result.append("Status code: ");
result.append(this.status.ordinal());
result.append(" (");
result.append(this.status.toString());
if (running) result.append(" (Archive running)");
if (calibrationPresent) result.append(" (Calibration file present)");
result.append(")\n");
return result.toString();
}
}