package center.system.msg;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import ru.vassaev.core.PrmInterface;
import ru.vassaev.core.exception.SysException;
import ru.vassaev.core.io.ByteMsg;
import ru.vassaev.core.io.CloseableOutputStream;
import ru.vassaev.core.types.StringList;
import ru.vassaev.core.util.Strings;
public class TPTPMsg extends ByteMsg {
public static final byte SOH = 0x01;
public static final byte STX = 0x02;
public static final byte EOT = 0x04;
public static final byte ENQ = 0x05;
public static final byte ACK = 0x06;
public static final byte CR = 0x0D;
public static final byte NAK = 0x15;
private static final byte ETX = 0x03;
private static final byte FLD = 0x1C;
private int len = 0;
public static String charset = "ibm866";
private final Map<String, byte[]> data = new HashMap<String, byte[]>();
public int getType() {
return type;
}
public void reset() {
data.clear();
type = 0;
len = 0;
}
private byte type = ENQ;
private byte[] header = new byte[48];
public ArrayList<byte[]> getMsg() throws SysException {
ArrayList<byte[]> r = new ArrayList<byte[]>();
int lrc = 0;
int i;
byte b;
byte[] add;
byte[] val;
r.add(new byte[] { type });
if (type != STX && type != SOH)
return r;
add = new byte[header.length];
for (i = 0; i < header.length; i++) {
b = header[i];
lrc ^= b;
add[i] = b;
}
r.add(add);
for (Map.Entry<String, byte[]> e : data.entrySet()) {
val = e.getValue();
add = new byte[2 + val.length];
lrc ^= FLD;
add[0] = FLD;
try {
b = e.getKey().getBytes(charset)[0];
} catch (UnsupportedEncodingException e1) {
throw new SysException(e1);
}
lrc ^= b;
add[1] = b;
for (i = 0; i < val.length; i++) {
b = val[i];
lrc ^= b;
add[i + 2] = b;
}
r.add(add);
}
lrc ^= ETX;
r.add(new byte[] { ETX, (byte) (0xff & lrc) });
return r;
}
public int getLengthMsg() {
if (type != STX && type != SOH)
return 1;
return (1 // STX || SOH
+ header.length // HEADER
+ (data.size() * 2) + len // (FLD + NAME + DATA) * N
+ 1 // ETX
+ 1); // LRC
}
public int getLengthFull() {
return getLengthMsg();
}
private void setField0(String key, String val) throws SysException {
byte[] dta = data.remove(key);
if (dta != null)
len = len - dta.length;
if (val != null) {
try {
dta = val.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new SysException(e);
}
data.put(key, dta);
len += dta.length;
}
}
private final PrmInterface prms = new Prm();
public PrmInterface getPrmInterface() throws SysException {
return prms;
}
public class Prm implements PrmInterface {
private void setFieldHeader(String key, String val) throws SysException {
byte[] r;
try {
r = val.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new SysException(e);
}
if ("DeviceType".equals(key)) {
header[0] = r[0];
header[1] = r[1];
} else if ("TransmissionNumber".equals(key)) {
header[2] = r[0];
header[3] = r[1];
} else if ("TerminalID".equals(key)) {
System.arraycopy(r, 0, header, 4, 16);
} else if ("EmployeeID".equals(key)) {
System.arraycopy(r, 0, header, 20, 6);
} else if ("CurrentDate".equals(key)) {
System.arraycopy(r, 0, header, 26, 6);
} else if ("CurrentTime".equals(key)) {
System.arraycopy(r, 0, header, 32, 6);
} else if ("MessageType".equals(key)) {
header[38] = r[0];
} else if ("MessageSubType".equals(key)) {
header[39] = r[0];
} else if ("TransactionCode".equals(key)) {
header[40] = r[0];
header[41] = r[1];
} else if ("ProcessingFlag1".equals(key)) {
header[42] = r[0];
} else if ("ProcessingFlag2".equals(key)) {
header[43] = r[0];
} else if ("ProcessingFlag3".equals(key)) {
header[44] = r[0];
} else if ("ResponseCode".equals(key)) {
header[45] = r[0];
header[46] = r[1];
header[47] = r[1];
}
}
private String getFieldHeader(String key) throws SysException {
try {
if ("DeviceType".equals(key)) {
return new String(header, 0, 2, charset);
} else if ("TransmissionNumber".equals(key)) {
return new String(header, 2, 2, charset);
} else if ("TerminalID".equals(key)) {
return new String(header, 4, 16, charset);
} else if ("EmployeeID".equals(key)) {
return new String(header, 20, 6, charset);
} else if ("CurrentDate".equals(key)) {
return new String(header, 26, 6, charset);
} else if ("CurrentTime".equals(key)) {
return new String(header, 32, 6, charset);
} else if ("MessageType".equals(key)) {
return new String(header, 38, 1, charset);
} else if ("MessageSubType".equals(key)) {
return new String(header, 39, 1, charset);
} else if ("TransactionCode".equals(key)) {
return new String(header, 40, 2, charset);
} else if ("ProcessingFlag1".equals(key)) {
return new String(header, 42, 1, charset);
} else if ("ProcessingFlag2".equals(key)) {
return new String(header, 43, 1, charset);
} else if ("ProcessingFlag3".equals(key)) {
return new String(header, 44, 1, charset);
} else if ("ResponseCode".equals(key)) {
return new String(header, 45, 3, charset);
}
return null;
} catch (UnsupportedEncodingException e) {
throw new SysException(e);
}
}
public void setField(String key, String val) throws SysException {
if (key == null)
return;
if (key.length() > 1) {
if ("type".equals(key)) {
byte type = (byte) (0xff & Strings.parseIntegerNvl(val, STX));
if (type == STX || type == SOH ||
type == EOT || type == ACK || type == CR || type == NAK || type == ENQ)
TPTPMsg.this.type = type;
else
throw new SysException("The type of message is incorrect");
} else
setFieldHeader(key, val);
return;
}
setField0(key, val);
}
public String getField(String key) throws SysException {
if (key == null)
return null;
if (key.length() > 1) {
if ("type".equals(key)) {
return String.valueOf(type);
}
return getFieldHeader(key);
}
byte[] dta = data.get(key);
if (dta == null)
return null;
try {
return new String(dta, charset);
} catch (UnsupportedEncodingException e) {
throw new SysException(e);
}
}
public byte[] getByteField(String key) throws SysException {
if (key == null)
return null;
if (key.length() > 1)
try {
if ("type".equals(key)) {
return String.valueOf(type).getBytes(charset);
}
return getFieldHeader(key).getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new SysException(e);
}
return data.get(key);
}
public void clearField(String key) throws SysException {
setField(key, null);
}
public boolean isPresentField(String key) throws SysException {
if (key == null)
return false;
if (key.length() > 1) {
if ("type".equals(key)) {
return true;
}
return (getFieldHeader(key) != null);
}
return data.get(key) != null;
}
public void clearFields() throws SysException {
len = 0;
data.clear();
}
public StringList getFieldNames() {
StringList sl = new StringList();
sl.add("type");
if (type == STX || type == SOH) {
sl.add("DeviceType");
sl.add("TransmissionNumber");
sl.add("TerminalID");
sl.add("EmployeeID");
sl.add("CurrentDate");
sl.add("CurrentTime");
sl.add("MessageType");
sl.add("MessageSubType");
sl.add("TransactionCode");
sl.add("ProcessingFlag1");
sl.add("ProcessingFlag2");
sl.add("ProcessingFlag3");
sl.add("ResponseCode");
sl.addAll(data.keySet());
}
return sl;
}
}
public String getKey() throws SysException {
return null;
}
public void setKey(String key) throws SysException {
}
public CloseableOutputStream getOutputStream() throws IOException {
return new MessageOutputStream();
}
private class MessageOutputStream extends CloseableOutputStream {
private int i = 0;
private int pos = 0;
private int ll = 0;
private StringBuffer sb = new StringBuffer();
private char fld;
private int lrc = 0;
public void write(int b) throws IOException {
ll ++;
if (b == -1 && i >= 0)
throw new IOException("The stream isn't comleted (pos = " + ll + ")");
if (i < 0) // Если поток закрыт
throw new IOException("The stream is already closed");
// System.out.println("WRITE:"+(char)b);
switch (i) {
case 0: { // Type
type = (byte) (b & 0xff);
if (type == EOT || type == ACK || type == CR || type == NAK || type == ENQ) {
i = -1;
} else if (type == STX || type == SOH) {
i++;
pos = 0;
} else
throw new IOException("The type of message is incorrect");
break;
}
case 1: {// Header
lrc ^= b;
header[pos] = (byte) (b & 0xff);
pos++;
if (pos == header.length) {
i++;
pos = 0;
}
break;
}
case 2: {// Fields
byte bt = (byte) (b & 0xff);
lrc ^= b;
if (pos == 0) {
if (bt == ETX) {
i++;
break;
}
if (bt != FLD)
throw new IOException("Incorrect fields' starting (" + i + ","
+ pos + ", pos = " + ll + ", byte = " + b + ")");
pos++;
break;
} else if (pos == 1) {
if (bt == FLD)
throw new IOException("Incorrect field's starting (" + i + ","
+ pos + ") (pos = " + ll + ")");
fld = (char) bt;
pos++;
break;
}
try {
if (bt == FLD) {
setField0(Character.toString(fld), sb.toString());
sb.setLength(0);
pos = 1;
} else if (bt == ETX) {
setField0(Character.toString(fld), sb.toString());
i++;
pos = 0;
} else
sb.append((char) bt);
} catch (SysException e) {
throw new IOException(e);
}
break;
}
case 3: {//LRC
if ((0xff & lrc) != (0xff & b))
throw new IOException("Incorrect LRC (pos = " + ll + ")");
i = -1;
}
}
}
public void close() throws IOException {
i = -1;
pos = -1;
}
public boolean isClosed() {
return (i == -1);
}
}
}