package com.cisdi.data.emserver.gateway.impl;

import java.nio.charset.Charset;
import java.util.Set;

import io.netty.util.CharsetUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.buf.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cisdi.data.common.utils.Strings;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.ByteOrder;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
import com.cisdi.data.sdk.service.PassthroughService;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.service.SendService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.google.common.collect.Sets;

import io.netty.buffer.ByteBuf;

/**
 * 
* <p>Title: StandardIoSession.java</p>
* <p>Description: 标准Socket协议会话实现</p>
* @author lhp
* @date 2019年2月12日
* @version 1.0
 */
public class EmiaProIoSession extends AbstractIoSession implements IoSession {

	private long lastAliveTime = System.currentTimeMillis();

	private static Logger logger = LoggerFactory.getLogger(EmiaProIoSession.class);
	
	private EmiaProSessionFactory factory = null;
	
	private String deviceId = null;
	
	private Short prevSeq = EmiaProConsts.Dummy_Sequence;
	
	protected Set<String> clientDeviceIds = Sets.newConcurrentHashSet();

	/**
	 * 如果有值，代表所有会话都使用这一个设备id，且允许多会话共享此一个设备id，不T除旧会话
	 */
	private String onlyOneDeviceId;
	
	public EmiaProIoSession(EmiaProSessionFactory factory, String onlyOneDeviceId) {
		super();
		this.factory = factory;
		this.onlyOneDeviceId = onlyOneDeviceId;
	}

	@Override
	public void onRead(Object message) {
		
		ByteOrder byteOrder = socketGateway == null ? ByteOrder.BIGENDIAN : socketGateway.getInstanceVo().getByteOrder();
		
		int length = ((ByteBuf)message).readableBytes();
		ByteBuf inBuf = (ByteBuf)message;
		String data=inBuf.toString(CharsetUtil.UTF_8);
		//剔除分隔符,
		data=data.replace(",","");
		Integer readerIndex = null;
		
		try {
			// 预备处理透传
			if(socketGateway != null && Boolean.TRUE.equals(socketGateway.getInstanceVo().getNeedPassthrough())) {
				readerIndex = inBuf.readerIndex();
			}

			if(socketGateway!= null && Boolean.TRUE.equals(socketGateway.getInstanceVo().getLogOpen())) {
				logger.info("EMIA-PRO {} 报文长度:{} vo:{} ", getChannel(), length, data);
			}

			
			if(serviceProvider != null && socketGateway != null&& onlyOneDeviceId!=null) {
				String runId = socketGateway.getInstanceVo().getRunId();
				RouteService routeService = (RouteService)serviceProvider.getByName(ServiceName.Route);
				DeviceVo deviceVo = routeService.findDeviceByDeviceId(onlyOneDeviceId);
				if(deviceVo == null || !Strings.equals(runId, deviceVo.getRunId())) {
					logger.error("查找不到 deviceId={} 的设备或此设备和本连接未正确配置关联，关闭当前会话", onlyOneDeviceId);
					close();
				}
			}

			// 需要检查之前是否存在，必须为多设备支持才如此， 如果存在，则T掉之前的会话
			if(factory != null && onlyOneDeviceId != null) {
				IoSession ioSession = factory.getSessionByDeviceId(onlyOneDeviceId);
				// 发现了已有设备会话，T掉
				if(ioSession != null && ioSession != this) {
					logger.error("发现设备：{}已存在会话:{}，同一设备只能绑定一个会话，自动将旧会话关闭",
							onlyOneDeviceId, ioSession.getChannel());
					EmiaProIoSession session = (EmiaProIoSession)ioSession;
					session.close();
				}
				factory.newDeviceConnect(onlyOneDeviceId, this);
			}
			
			lastAliveTime = System.currentTimeMillis();

			
			if(StringUtils.isNotBlank(data) && serviceProvider != null && socketGateway != null) {
				SendService service = (SendService)serviceProvider.getByName(ServiceName.Send);
				
				SocketMessage socketMessage = socketGateway.buildSocketMessage();
				socketMessage.setDeviceId(onlyOneDeviceId);
				socketMessage.setData(data.getBytes());
				socketMessage.setMsgKey("default");
                socketMessage.getPropsMap().put("charset",  Charset.forName("UTF-8"));
				
				service.sendMessage(socketMessage);
			}else {
				String hexString = HexUtils.toHexString(data.getBytes());
				logger.info("长度:{},报文:{}", data.length(), hexString);
			}
		} finally {
			if(readerIndex != null) { // 需要透传
				inBuf.readerIndex(readerIndex);
				passthrough(inBuf);
			}
		}
		
	}
	
	private void passthrough(ByteBuf passthroughBuf) {
		try {
			if(serviceProvider != null && socketGateway != null) {
				PassthroughService service = (PassthroughService)serviceProvider.getByName(ServiceName.Passthrough);
				service.transfer(passthroughBuf, socketGateway.getInstanceVo().getPassthroughAddress());
			}			
		}catch (Exception e) {
		    logger.error("tcp标准协议透传失败：" + e.getLocalizedMessage(), e);
		}
	}

	@Override
	public void onOpen() {
		super.onOpen();
		logger.info("建立连接，channel:{}", getChannel());
	}
	
	@Override
	public void onClose() {
		super.onClose();
		factory = null;
	}
	
	public void close() {
		if(getChannel() != null) { 
			try {
				getChannel().close().sync();
			} catch (InterruptedException e) {
				logger.warn(e.getLocalizedMessage(), e);
			} 
		}
	}
	
	private String gwPrefixCache = null;
	
	public String gwPrefix() {
		if(gwPrefixCache != null) {
			return gwPrefixCache;
		}
		
		gwPrefixCache = "";
		if(socketGateway != null && socketGateway.getInstanceVo() != null) {
			gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
		}else {
			gwPrefixCache = "连接:" + getChannel() + " ";
		}
		
		return gwPrefixCache;
	}

	public long getLastAliveTime() {
		return lastAliveTime;
	}

	@Override
	public String[] getDeviceIds() {
		String cpDeviceId = deviceId;
		String[] result = new String[cpDeviceId == null ? 0 : 1];
		if(cpDeviceId != null) {
			result[0] = cpDeviceId;
		}
		return result;
	}
}