package com.szpg.plc.protocol.fins.frame;

import com.szpg.plc.protocol.fins.FINSConstants;
import com.szpg.plc.util.ByteUtil;
import com.szpg.plc.util.Bytes;

public class FINSByteFrameTool {
	
	/**
	 * 获取数据帧的长度字
	 * 位于整个消息帧的5-8字节
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static byte[] getFrameLength(byte[] finsBytes) {
		if (finsBytes.length < 8) {
			return new byte[] {0x00, 0x00, 0x00, 0x00};
		}
		
		byte[] lengthByte = new byte[] {finsBytes[4], finsBytes[5], finsBytes[6], finsBytes[7]};
		return lengthByte;
	}
	
	/**
	 * 获取帧的功能码
	 * 位于整个消息帧的9-12字节
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static String getCommandStr(byte[] finsBytes) {
		if (finsBytes.length < 12) {
			return "";
		}
		
		return ByteUtil.binToHexString(finsBytes, 16, 24);
	}
	
	/**
	 * 获取帧的错误代码
	 * 位于整个消息帧的13-16字节
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static String getErrorCodeStr(byte[] finsBytes) {
		if (finsBytes.length < 16) {
			return "";
		}
		
		return ByteUtil.binToHexString(finsBytes, 24, 32);
	}
	
	/**
	 * 获取帧的TEXT域数据
	 * 代表用户数据
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static String getTextStr(byte[] finsBytes) {
		return ByteUtil.binToHexString(getText(finsBytes));
	}
	
	/**
	 * 获取帧的TEXT域数据
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static byte[] getText(byte[] finsBytes) {
		if (finsBytes.length < 16) {
			return null;
		}
		
		Bytes textBytes = new Bytes();
		for (int i = 16; i < finsBytes.length; i++) {
			textBytes.append(finsBytes[i]);
		}
		
		return textBytes.toBytes();
	}
	
	/**
	 * 获取ICF字节
	 * 位于TEXT区的第一个字节
	 * 如果是握手响应消息则没有该字节
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static String getControlICF(byte[] finsBytes) {
		byte[] text = getText(finsBytes);
		
		if (null != text && text.length > 10) 
			return ByteUtil.binToHexString(new byte[] {text[0]});
		else 
			return "";
	}
	
	/**
	 * 获取目标地址字符串
	 * 目标地址=目标网络号+目标节点号+目标单元号
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static String getControlDest(byte[] finsBytes) {
		byte[] text = getText(finsBytes);
		
		if (null != text && text.length > 10) 
			return ByteUtil.binToHexString(new byte[] {text[3], text[4], text[5]});
		else 
			return "";
	}
	
	/**
	 * 获取目标地址字符串
	 * 目标地址=目标网络号+目标节点号+目标单元号
	 * 从frame对象中获取
	 * 
	 * @param finsFrame
	 * @return
	 */
	public static String getControlDest(FINSByteFrame finsFrame) {
		return ByteUtil.binToHexString(new byte[] {finsFrame.TEXT_CONTROL_SNA, finsFrame.TEXT_CONTROL_SA1, finsFrame.TEXT_CONTROL_SA2});
	}
	
	/**
	 * 获取源地址字符串
	 * 源地址=源网络号+源节点号+源单元号
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static String getControlSour(byte[] finsBytes) {
		byte[] text = getText(finsBytes);
		
		if (null != text && text.length > 10) 
			return ByteUtil.binToHexString(new byte[] {text[6], text[7], text[8]});
		else 
			return "";
	}
	
	/**
	 * 获取SID号，作为命令类型使用
	 * @param finsBytes
	 * @return
	 */
	public static String getControlSID(byte[] finsBytes) {
		byte[] text = getText(finsBytes);
		
		if (null != text && text.length > 10) 
			return ByteUtil.binToHexString(new byte[] {text[9]});
		else 
			return "00";
	}
	
	/**
	 * 获取命令代码
	 * 0x0101=读取内存，0x0102=写内存
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static String getFinsCommandCode(byte[] finsBytes) {
		byte[] text = getText(finsBytes);
		
		if (null != text && text.length >= 10) 
			return ByteUtil.binToHexString(new byte[] {text[10], text[11]});
		else 
			return "";
	}
	
	/**
	 * 获取读取的数据内容
	 * 不包括END CODE
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static byte[] getDataWithoutEndCode(byte[] finsBytes) {
		byte[] text = getText(finsBytes);
		
		if (null != text && text.length > 12) {
			Bytes dataBody = new Bytes();
			for (int i = 14; i < text.length; i++) {
				dataBody.append(text[i]);
			}
			
			return dataBody.toBytes();
		} else {
			return null;
		}
	}
	
	
	/**
	 * 获取读取的数据内容
	 * 不包括END CODE
	 * 
	 * @param finsFrame
	 * @return
	 */
	public static byte[] getDataWithoutEndCode(FINSByteFrame finsFrame) {
		byte[] dataBody = finsFrame.TEXT_DATA_BODY;
		
		Bytes dataByte = new Bytes();
		for (int i = 4; i < dataBody.length; i++) {
			dataByte.append(dataBody[i]);
		}
		
		return dataByte.toBytes();
	}
	
	
	/**
	 * 获取包含END CODE在内的用户数据域
	 * 
	 * @param finsBytes
	 * @return
	 */
	public static byte[] getDataWithEndCode(byte[] finsBytes) {
		byte[] text = getText(finsBytes);
		
		if (null != text && text.length > 20) {
			Bytes dataBody = new Bytes();
			for (int i = 23; i < text.length; i++) {
				dataBody.append(text[i]);
			}
			
			return dataBody.toBytes();
		} else {
			return null;
		}
	}
	

	/**
	 * 生成控制域10个字节的内容
	 * 
	 * @param dest 目标地址：网络号+节点号+单元号
	 * @param sour 源地址：网络号+节点号+单元号
	 * @param sid 服务号：用于标识命令类型
	 * @return
	 */
	public static byte[] buildFrameControl(String dest, String sour, String sid) {
		byte[] control = new byte[10];
		
		// 命令类型位固定为1，需要响应标志位固定为0，表示从上位机发送给PLC端的消息，需要PLC响应
		control[0] = (byte) 0x80; // ICF字节
		control[1] = FINSConstants.RSV; // RSV字节
		control[2] = FINSConstants.GCT; // GCT字节
		
		byte[] destByte = ByteUtil.hexStringToBytes(dest);
		byte[] sourByte = ByteUtil.hexStringToBytes(sour);

		control[3] = destByte[0]; //目标网络号
		control[4] = destByte[1]; //目标节点号
		control[5] = destByte[2]; //目标单元号
		
		control[6] = sourByte[0]; //源网络号
		control[7] = sourByte[1]; //源节点号
		control[8] = sourByte[2]; //源单元号
		
//		control[9] = FINSConstants.SID; // SID字节
		control[9] = ByteUtil.hexStringToBytes(sid, 1)[0];

		return control;
	}

	/**
	 * 生成地址域
	 * 
	 * @param address
	 * @return
	 */
	public static byte[] buildFrameAddress(String address) {
		if (address.length() != 10)
			return null;

		Bytes addressBytes = new Bytes();
		
		byte[] addvcdBytes = ByteUtil.bcdStringToBytes(address.substring(0, 6));
		byte[] dtuidBytes = ByteUtil.hexStringToBytes(address.substring(6, 10));
		
		addressBytes.append(addvcdBytes).append(dtuidBytes[1]).append(dtuidBytes[0]);

		return addressBytes.toBytes();
	}

}
