package center.system.msg;
import ru.vassaev.core.exception.SysException;
import java.io.*;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import java.util.Iterator;
import ru.vassaev.core.types.StringList;
import ru.vassaev.core.util.Bytes;
import ru.vassaev.core.io.CloseableOutputStream;
import ru.vassaev.core.io.ByteMsg;
import ru.vassaev.core.PrmInterface;
/**
* Сообщение формата CSNV (РУКАРД)
*
* @author Vassaev A.V.
* @version 1.1
*/
public class CSNVMsg extends ByteMsg {
private Map<String, byte[]> btf = new TreeMap<String, byte[]>();
private String character = "ibm866";
private int ll = 2; //Длина буфера под длину сообщения
private int len = 0; //Длина тела сообщения
private byte delimiter = 0x1c;
public CSNVMsg() {
}
public CSNVMsg(String character) {
this.character = character;
}
public void reset() {
btf.clear();
len = 0;
}
/**
* Получить длину только сообщения
*
* @return int
*/
public int getLengthMsg() {
return len;
}
/**
* Получить полную длину сообщения, включая поля длины сообщения
*
* @return int
*/
public int getLengthFull() {
return getLengthMsg() + ll;
}
private void setField(byte[] val, int len) throws SysException {
if ((val == null) || (val.length == 0)) {
prms.clearField("");
return;
}
String fld;
try {
fld = new String(val, 0, len, character);
} catch (UnsupportedEncodingException ex) {
throw new SysException(ex);
}
int p = fld.indexOf('=');
if (p >= 0)
prms.setField(fld.substring(0, p), fld.substring(p + 1));
else
prms.setField("", fld);
}
/**
* Сообщение в виде последовательности массивов байт
*
* @return ArrayList
*/
public ArrayList<byte[]> getMsg() {
ArrayList<byte[]> ls = new ArrayList<byte[]>();
Iterator<byte[]> itr = btf.values().iterator();
int l = getLengthMsg();
int fl = l + ll;
byte[] v = new byte[fl];
for (int i = ll - 1; i >= 0; i--) {
v[i] = (byte) (l & 0xff);
l = l >> 8;
}
int i = ll;
while (itr.hasNext()) {
byte[] val = itr.next();
int s;
if ((val != null) && ((s = val.length) > 0)) {
System.arraycopy(val, 0, v, i, s);
i = i + s;
if (i < fl) {
v[i] = delimiter;
i++;
}
}
}
ls.add(v);
return ls;
}
public String getKey() throws SysException {
return prms.getField("STAN");
}
public void setKey(String key) throws SysException {
prms.setField("STAN", key);
}
private class MessageOutputStream extends CloseableOutputStream {
private int i = 0;
private int pos = 0;
private byte[] lengthb = new byte[ll];
private byte[] current = new byte[2048];
private int length = 0;
public void write(int b) throws IOException {
if (i < 0) // Если поток закрыт
throw new IOException("The stream is already closed");
if (i == 0) { // Общая длина - LL байт
lengthb[pos] = (byte) b;
pos++;
if (pos == lengthb.length) {
length = Bytes.byteReversToInt(lengthb);
i++;
pos = 0;
}
return;
}
byte bb = (byte) (b & 0xff);
if (bb == delimiter) {
try {
setField(current, pos);
} catch (SysException e) {
throw new IOException(e.getMessage());
}
i++;
pos = 0;
length--;
if (length <= 0) {
close();
}
} else {
current[pos] = bb;
pos++;
length--;
if (length <= 0) {
try {
setField(current, pos);
} catch (SysException e) {
throw new IOException(e.getMessage());
}
close();
}
}
}
public void close() throws IOException {
i = -1;
pos = -1;
}
public boolean isClosed() {
return (i == -1);
}
}
/**
* Получить входящий поток сообщения
*
* @return OutputStream
*/
public CloseableOutputStream getOutputStream() throws IOException {
return new MessageOutputStream();
}
private final PrmInterface prms = new Prm();
public PrmInterface getPrmInterface() throws SysException {
return prms;
}
public class Prm implements PrmInterface {
/**
* Установить поле
*
* @param name String
* @param val byte[]
*/
public void setField(String name, String val) throws SysException {
if ((val == null) || (val.length() == 0)) {
clearField(name);
return;
}
String nm = name;//name.toUpperCase();
byte[] n;
try {
nm = ((nm != null) && (nm.length() > 0)) ? nm + "=" : "";
n = (nm + val).getBytes(character);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
byte[] o = btf.put(name, n);
if (o != null)
len = len - o.length;
else if (btf.size() > 1)
len = len + 1;
len += n.length;
}
/**
* Очистить поле
*
* @param name String
*/
public void clearField(String name) {
byte[] o = (btf.remove(name/*.toUpperCase()*/));
if (o != null) {
len = len - o.length;
if (btf.size() > 0)
len = len - 1;
}
}
public boolean isPresentField(String key) throws SysException {
return btf.get(key/*.toUpperCase()*/) != null;
}
public void clearFields() throws SysException {
ArrayList<String> flds = getFieldNames();
for (int i = flds.size() - 1; i >= 0; i--)
clearField(flds.get(i));
}
/**
* Получить поле
*
* @param name String
* @return byte[]
*/
public String getField(String name) {
byte[] o = btf.get(name);
if (o == null)
return null;
String os;
try {
os = new String(o, 0, o.length, character);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
int i = os.indexOf('=');
if (i >= 0)
return os.substring(i + 1);
else
return os;
}
public StringList getFieldNames() {
StringList ls = new StringList();
for (String s : btf.keySet())
ls.add(s);
return ls;
}
public byte[] getByteField(String key) throws SysException {
// TODO Auto-generated method stub
return null;
}
}
public void sendTo(OutputStream os) throws IOException {
ArrayList<byte[]> res = getMsg();
if (res.size() == 1) {
byte[] f = res.get(0);
os.write(f);
os.flush();
}
}
}