DirectiveBuffer.java 9.17 KB
package com.bsth.vehicle.directive.buffer;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.bsth.entity.realcontrol.ScheduleRealInfo;
import com.bsth.service.realcontrol.buffer.ScheduleBuffer;
import com.bsth.vehicle.common.CommonMapped;
import com.bsth.vehicle.directive.MsgIdGenerator;
import com.bsth.vehicle.directive.entity.Directive60;
import com.bsth.vehicle.directive.entity.DirectiveReply;
import com.bsth.vehicle.directive.entity.Directive80;
import com.bsth.vehicle.directive.entity.DirectiveC0;
import com.bsth.vehicle.directive.entity.DirectiveC0.DirectiveC0Data;
import com.bsth.vehicle.directive.entity.Directive64;
import com.bsth.vehicle.directive.repository.Directive60Repository;
import com.bsth.vehicle.directive.repository.Directive80Repository;
import com.bsth.vehicle.directive.repository.LineChangeRepository;
import com.bsth.vehicle.directive.service.DirectiveService;
import com.bsth.websocket.handler.RealControlSocketHandler;
import com.google.common.collect.ArrayListMultimap;

/**
 * 
 * @ClassName: DirectiveBuffer 
 * @Description: TODO(调度指令缓存) 
 * @author PanZhao
 * @date 2016年6月7日 下午3:24:19 
 *
 */
@Component
public class DirectiveBuffer {
	
	Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	Directive80Repository d80Repository;
	
	@Autowired
	LineChangeRepository d64Repository;
	
	@Autowired
	DirectiveService directiveService60;
	
	
	/**
	 * 等待入库的调度指令
	 */
	public static LinkedList<Directive60> transientList;
	
	/**
	 * 线路切换指令 64
	 */
	public static Map<String, Directive64> changeMap;
	
	/**
	 * 当日60指令缓存
	 */
	private static Map<Integer, Directive60> directiveMap;
	
	@Autowired
	Directive60Repository d60Repository;
	
	/**
	 * 驾驶员上报数据
	 * {K: 线路编码}
	 */
	private static ArrayListMultimap<Integer, Directive80> reportMultiMap;
	
	@Autowired
	RealControlSocketHandler socketHandler;
	
	static{
		clear();
	}
	
	public static void put(Directive60 directive){
		directiveMap.put(directive.getMsgId(), directive);
	}
	
	/**
	 * 
	 * @Title: reply 
	 * @Description: TODO(指令 46,47 响应) 
	 * @throws
	 */
	public void reply(DirectiveReply reply){
		Integer msgId = reply.getMsgId();
		if(msgId == null){
			logger.error("reply error , msgId is null.");
			return;
		}
		
		Directive60 directive = directiveMap.get(msgId);
		
		if(null == directive){
			//无效的响应
			return;
		}
		
		switch (reply.getStatus()) {
		case 0:
			//失败
			directive.setReply46((short)-1);
			break;

		case 1:
			//发送成功
			directive.setReply46((short)0);
			break;
		case 2:
			//驾驶员阅读
			directive.setReply47((short)0);
			break;
		}
		
		ScheduleRealInfo sch = directive.getSch();
		
		if(null == sch)
			return;
		
		//调度指令回复
		if(directive.isDispatch()){
			//更新班次状态
			sch.setDirectiveState(reply.getStatus() * 100);
			ScheduleBuffer.persistentList.add(sch);
			//通知页面
			directiveService60.sendDirectiveToPage(sch);
		}
		//运营状态指令回复
		else if(directive.getData().getDispatchInstruct() == 0x03){
			sch.setOpDirectiveState(reply.getStatus() * 100);
			ScheduleBuffer.persistentList.add(sch);
		}
		transientList.add(directive);
	}
	
	/**
	 * 
	 * @Title: reply64 
	 * @Description: TODO(64 协议响应) 
	 * @throws
	 */
	public void reply64(JSONObject json){
		String key = json.getString("deviceId") + "_" + json.getString("timestamp");
		
		Directive64 change = changeMap.get(key);
		
		if(null == change)
			logger.warn("64响应 -找不到请求源,json: " + json);
		else if(change.getRespAck() != null)
			logger.warn("64响应 -重复响应,json: " + json);
		else{
			JSONObject data = json.getJSONObject("data");
			
			if(null == data)
				logger.warn("64响应 data is null ,json: " + json);
			else{
				change.setRespAck(data.getShort("requestAck"));
				//响应入库
				d64Repository.save(change);
			}
		}
	}
	
	/**
	 * 
	 * @Title: jsyReport 
	 * @Description: TODO(80 驾驶员上报) 
	 * @throws
	 */
	public void jsyReport(Directive80 report){
		//将托管的线路自动处理掉
		Integer lineCode = report.getData().getLineId();
		//Integer status = ScheduleBuffer.trustMap.get(lineCode);
		//请求代码
		//Short requestCode = report.getData().getRequestCode();
		//托管
		/*if(null == status || status == 0){
			//自动处理出场请求
			if(requestCode == 0xA3){
				DirectiveC0 c0 = createC0(report, (short)0x06);
				HttpUtils.postJson(JSON.toJSONString(c0));
				report.setC0(c0);
				d80Repository.save(report);
			}
		}*/
		
		//实时入库
 		d80Repository.save(report);
		
		reportMultiMap.put(lineCode, report);
		//推送到页面
		report.getData().setNbbm(CommonMapped.vehicDeviceBiMap.get(report.getDeviceId()));
		JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(report));
		json.put("fn", "report80");
 		socketHandler.sendMessageToLine(lineCode, json.toJSONString());
	}
	
	/**
	 * 
	 * @Title: createC0 
	 * @Description: TODO(生成C0数据) 
	 * @param @param ack
	 * @throws
	 */
	public DirectiveC0 createC0(Directive80 report, short ack){
		DirectiveC0 c0 = new DirectiveC0();
		c0.setDeviceId(report.getDeviceId());
		c0.setTimestamp(report.getTimestamp());
		c0.setOperCode((short)0xC0);
		
		DirectiveC0Data data = new DirectiveC0Data();
		data.setOperCode2((short)0x86);
		data.setRequestAck(ack);
		
		c0.setData(data);
		return c0;
	}
	
	/**
	 * 
	 * @Title: saveAll 
	 * @Description: TODO(所有缓存里的指令全部入库) 
	 */
	public void saveAll(){
		//未回复的60指令入库
		Collection<Directive60> ds = directiveMap.values();
		List<Directive60> pList = new ArrayList<>();
		for(Directive60 d : ds){
			if(d.getReply47() == null)
				pList.add(d);
		}
		d60Repository.save(directiveMap.values());
		
		//未回复的64指令入库
		Collection<Directive64> ds64 = changeMap.values();
		List<Directive64> pList2 = new ArrayList<>();
		for(Directive64 d : ds64){
			if(d.getRespAck() == null)
				pList2.add(d);
		}
		d64Repository.save(pList2);
	}
	
	/**
	 * 
	 * @Title: clear 
	 * @Description: TODO(清理缓存) 
	 * @throws
	 */
	public static void clear(){
		transientList = new LinkedList<>();
		directiveMap = new HashMap<>();
		reportMultiMap = ArrayListMultimap.create();
		changeMap = new HashMap<>();
	}
	
	/**
	 * 
	 * @Title: recovery 
	 * @Description: TODO(从数据库恢复当天的指令数据到内存.) 
	 * @throws
	 */
	public void recovery(){
		clear();
		
		//设置msgId
		Integer maxMsgId = d60Repository.maxMsgId();
		MsgIdGenerator.setMsgId(maxMsgId ++);
		
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.HOUR_OF_DAY, 2);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.MILLISECOND, 0);
		//当天2点开始恢复
		long st = cal.getTimeInMillis()
			,ct = System.currentTimeMillis();
		
		//如果还不到2点,从前一天2点开始恢复
		if(ct < st){
			st -= (1000 * 60 * 60 * 24);
		}
		
		List<Directive60> d60List = d60Repository.findByGtTime(st);
		//恢复60下发指令
		for(Directive60 d : d60List){
			directiveMap.put(d.getMsgId(), d);
		}
		
		//恢复80驾驶员上报
		List<Directive80> d80List = d80Repository.findByGtTime(st);
		
		for(Directive80 d : d80List){
			d.getData().setNbbm(CommonMapped.vehicDeviceBiMap.get(d.getDeviceId()));
			reportMultiMap.put(d.getData().getLineId(), d);
		}
	}
	
	public static List<Directive80> findNoCofm80(Integer lineCode){
		List<Directive80> list = reportMultiMap.get(lineCode)
					,rs = new ArrayList<>();
		
		for(Directive80 d : list){
			if(!d.isConfirm())
				rs.add(d);
		}
		return rs;
	}
	
	public static Directive80 findById80(int id){
		Collection<Directive80> ds = reportMultiMap.values();
		
		Directive80 rs = null;
		for(Directive80 d : ds){
			if(d.getId() == id){
				rs = d;
				break;
			}
		}
		
		return rs;
	}
	
	/**
	 * 
	 * @Title: findAll 
	 * @Description: TODO(获取缓存里的全部指令) 
	 * @throws
	 */
	public static List<Object> findAll(){
		List<Object> all = new ArrayList<>();
		//60
		all.addAll(directiveMap.values());
		//64
		all.addAll(changeMap.values());
		return all;
	}
	
	public static class DComparator implements Comparator<Object>{

		@Override
		public int compare(Object o1, Object o2) {
			Long t1,t2;
			if(o1 instanceof Directive60)
				t1 = ((Directive60)o1).getTimestamp();
			else
				t1 = ((Directive64)o1).getTimestamp();
			
			if(o2 instanceof Directive60)
				t2 = ((Directive60)o2).getTimestamp();
			else
				t2 = ((Directive64)o2).getTimestamp();
			
			return (int) (t2 - t1);
		}
		
	}
}