Commit 662009325ca3f6ad79b7a4675f8e69ee762c48d8

Authored by 王通
1 parent b7825399

1.

src/main/java/com/bsth/data/gpsdata_v2/utils/GpsDataRecovery.java
1 -package com.bsth.data.gpsdata_v2.utils;  
2 -  
3 -import com.bsth.data.BasicData;  
4 -import com.bsth.data.gpsdata_v2.cache.GpsCacheData;  
5 -import com.bsth.data.gpsdata_v2.entity.GpsEntity;  
6 -import com.bsth.data.gpsdata_v2.handlers.*;  
7 -import com.bsth.util.db.DBUtils_MS;  
8 -import com.google.common.collect.ArrayListMultimap;  
9 -import org.slf4j.Logger;  
10 -import org.slf4j.LoggerFactory;  
11 -import org.springframework.beans.BeansException;  
12 -import org.springframework.context.ApplicationContext;  
13 -import org.springframework.context.ApplicationContextAware;  
14 -import org.springframework.jdbc.core.JdbcTemplate;  
15 -import org.springframework.jdbc.core.RowMapper;  
16 -import org.springframework.stereotype.Component;  
17 -  
18 -import java.sql.ResultSet;  
19 -import java.sql.SQLException;  
20 -import java.util.*;  
21 -import java.util.concurrent.CountDownLatch;  
22 -import java.util.concurrent.ExecutorService;  
23 -import java.util.concurrent.Executors;  
24 -  
25 -/**  
26 - * gps数据恢复  
27 - * Created by panzhao on 2016/12/24.  
28 - */  
29 -@Component  
30 -public class GpsDataRecovery implements ApplicationContextAware {  
31 -  
32 - static Logger logger = LoggerFactory.getLogger(GpsDataRecovery.class);  
33 -  
34 - public static boolean run;  
35 -  
36 - static ExecutorService threadPool = Executors.newFixedThreadPool(10);  
37 -  
38 - static GpsStateProcess gpsStateProcess;  
39 - static StationInsideProcess stationInsideProcess;  
40 - static InStationProcess inStationProcess;  
41 - static OutStationProcess outStationProcess;  
42 - static AbnormalStateProcess abnormalStateProcess;  
43 - static ReverseRouteProcess reverseRouteProcess;  
44 -  
45 - public void recovery() {  
46 - List<GpsEntity> list = loadData();  
47 -  
48 - //按线路分组数据  
49 - ArrayListMultimap<String, GpsEntity> listMap = ArrayListMultimap.create();  
50 - for (GpsEntity gps : list) {  
51 - if (gps.getNbbm() != null)  
52 - listMap.put(gps.getNbbm(), gps);  
53 - }  
54 -  
55 -  
56 - Set<String> keys = listMap.keySet();  
57 -  
58 - CountDownLatch count = new CountDownLatch(keys.size());  
59 - GpsComp comp = new GpsComp();  
60 - for (String nbbm : keys) {  
61 - Collections.sort(listMap.get(nbbm), comp);  
62 - threadPool.submit(new RecoveryThread(listMap.get(nbbm), count));  
63 - /*if(nbbm.equals("W1E-169"))  
64 - new RecoveryThread(listMap.get(nbbm), count).run();*/  
65 - /*if(lineId.equals("60028"))  
66 - new RecoveryThread(listMap.get(lineId), count).run();*/  
67 - }  
68 -  
69 - try {  
70 - count.await();  
71 - run = false;  
72 - logger.info("数据恢复完成....");  
73 - } catch (InterruptedException e) {  
74 - logger.error("", e);  
75 - }  
76 - }  
77 -  
78 - /**  
79 - * 加载当天的gps数据  
80 - *  
81 - * @return  
82 - */  
83 - public List<GpsEntity> loadData() {  
84 - Calendar calendar = Calendar.getInstance();  
85 - int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);  
86 -  
87 - String sql = "select DEVICE_ID,LAT,LON,TS,SPEED_GPS,LINE_ID,SERVICE_STATE,SERVER_TS from bsth_c_gps_info"; //+ dayOfYear;  
88 - JdbcTemplate jdbcTemplate = new JdbcTemplate(DBUtils_MS.getDataSource());  
89 -  
90 - List<GpsEntity> list =  
91 - jdbcTemplate.query(sql, new RowMapper<GpsEntity>() {  
92 - @Override  
93 - public GpsEntity mapRow(ResultSet rs, int rowNum) throws SQLException {  
94 - GpsEntity gps = new GpsEntity();  
95 -  
96 - gps.setDeviceId(rs.getString("DEVICE_ID"));  
97 - gps.setNbbm(BasicData.deviceId2NbbmMap.get(gps.getDeviceId()));  
98 - gps.setSpeed(rs.getFloat("SPEED_GPS"));  
99 - gps.setLat(rs.getFloat("LAT"));  
100 - gps.setLon(rs.getFloat("LON"));  
101 - gps.setLineId(rs.getString("LINE_ID"));  
102 - gps.setTimestamp(rs.getLong("TS"));  
103 - gps.setUpDown((byte) getUpOrDown(rs.getLong("SERVICE_STATE")));  
104 - gps.setServerTimestamp(rs.getLong("SERVER_TS"));  
105 - gps.setState((int) getService(rs.getLong("SERVICE_STATE")));  
106 - return gps;  
107 - }  
108 - });  
109 - return list;  
110 - }  
111 -  
112 - /**  
113 - * 获取运营状态  
114 - *  
115 - * @return -1无效 0运营 1未运营  
116 - */  
117 - public static byte getService(long serviceState) {  
118 - if ((serviceState & 0x00020000) == 0x00020000 || (serviceState & 0x80000000) == 0x80000000)  
119 - return -1;  
120 - return (byte) (((serviceState & 0x02000000) == 0x02000000) ? 1 : 0);  
121 - }  
122 -  
123 - /**  
124 - * 王通 2016/6/29 9:23:24 获取车辆线路上下行  
125 - *  
126 - * @return -1无效 0上行 1下行  
127 - */  
128 - public static int getUpOrDown(long serviceState) {  
129 - if ((serviceState & 0x00020000) == 0x00020000 || (serviceState & 0x80000000) == 0x80000000  
130 - || (serviceState & 0x01000000) == 0x01000000 || (serviceState & 0x08000000) == 0x08000000)  
131 - return -1;  
132 - return (((serviceState & 0x10000000) == 0x10000000) ? 1 : 0);  
133 - }  
134 -  
135 - @Override  
136 - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
137 - gpsStateProcess = applicationContext.getBean(GpsStateProcess.class);  
138 - stationInsideProcess = applicationContext.getBean(StationInsideProcess.class);  
139 - inStationProcess = applicationContext.getBean(InStationProcess.class);  
140 - outStationProcess = applicationContext.getBean(OutStationProcess.class);  
141 - abnormalStateProcess = applicationContext.getBean(AbnormalStateProcess.class);  
142 - reverseRouteProcess = applicationContext.getBean(ReverseRouteProcess.class);  
143 - }  
144 -  
145 - public static class GpsComp implements Comparator<GpsEntity> {  
146 -  
147 - @Override  
148 - public int compare(GpsEntity g1, GpsEntity g2) {  
149 - return g1.getTimestamp().compareTo(g2.getTimestamp());  
150 - }  
151 - }  
152 -  
153 - public static class RecoveryThread implements Runnable {  
154 - List<GpsEntity> list;  
155 - CountDownLatch count;  
156 -  
157 - RecoveryThread(List<GpsEntity> list, CountDownLatch count) {  
158 - this.list = list;  
159 - this.count = count;  
160 - }  
161 -  
162 - @Override  
163 - public void run() {  
164 - try {  
165 - //循环gps恢复数据  
166 - for (GpsEntity gps : list) {  
167 - try {  
168 -  
169 - /*if(gps.getTimestamp() >= 1511569544000L)  
170 - System.out.println("aaa");*/  
171 -  
172 - if(Math.abs(gps.getTimestamp() - gps.getServerTimestamp()) > 1000 * 60 * 20)  
173 - continue;  
174 -  
175 - gpsStateProcess.process(gps);//状态处理  
176 - stationInsideProcess.process(gps);//场站内外判定  
177 - reverseRouteProcess.process(gps);//反向路由处理  
178 -  
179 - abnormalStateProcess.process(gps);//超速越界  
180 -  
181 - inStationProcess.process(gps);//进站  
182 - outStationProcess.process(gps);//出站  
183 -  
184 - GpsCacheData.putGps(gps);//历史gps缓存  
185 - } catch (Exception e) {  
186 - logger.error("", e);  
187 - }  
188 - }  
189 - } finally {  
190 - count.countDown();  
191 - }  
192 - }  
193 - } 1 +package com.bsth.data.gpsdata_v2.utils;
  2 +
  3 +import com.bsth.data.BasicData;
  4 +import com.bsth.data.gpsdata_v2.cache.GpsCacheData;
  5 +import com.bsth.data.gpsdata_v2.entity.GpsEntity;
  6 +import com.bsth.data.gpsdata_v2.handlers.*;
  7 +import com.bsth.util.db.DBUtils_MS;
  8 +import com.google.common.collect.ArrayListMultimap;
  9 +import org.joda.time.DateTime;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
  12 +import org.springframework.beans.BeansException;
  13 +import org.springframework.context.ApplicationContext;
  14 +import org.springframework.context.ApplicationContextAware;
  15 +import org.springframework.jdbc.core.JdbcTemplate;
  16 +import org.springframework.jdbc.core.RowMapper;
  17 +import org.springframework.stereotype.Component;
  18 +
  19 +import java.sql.ResultSet;
  20 +import java.sql.SQLException;
  21 +import java.util.*;
  22 +import java.util.concurrent.CountDownLatch;
  23 +import java.util.concurrent.ExecutorService;
  24 +import java.util.concurrent.Executors;
  25 +
  26 +/**
  27 + * gps数据恢复
  28 + * Created by panzhao on 2016/12/24.
  29 + */
  30 +@Component
  31 +public class GpsDataRecovery implements ApplicationContextAware {
  32 +
  33 + static Logger logger = LoggerFactory.getLogger(GpsDataRecovery.class);
  34 +
  35 + public static boolean run;
  36 +
  37 + static ExecutorService threadPool = Executors.newFixedThreadPool(10);
  38 +
  39 + static GpsStateProcess gpsStateProcess;
  40 + static StationInsideProcess stationInsideProcess;
  41 + static InStationProcess inStationProcess;
  42 + static OutStationProcess outStationProcess;
  43 + static AbnormalStateProcess abnormalStateProcess;
  44 + static ReverseRouteProcess reverseRouteProcess;
  45 +
  46 + public void recovery(String lineCode, DateTime dateTime) {
  47 + List<GpsEntity> list = loadData(lineCode, dateTime);
  48 +
  49 + //按线路分组数据
  50 + ArrayListMultimap<String, GpsEntity> listMap = ArrayListMultimap.create();
  51 + for (GpsEntity gps : list) {
  52 + if (gps.getNbbm() != null)
  53 + listMap.put(gps.getNbbm(), gps);
  54 + }
  55 +
  56 +
  57 + Set<String> keys = listMap.keySet();
  58 +
  59 + CountDownLatch count = new CountDownLatch(keys.size());
  60 + GpsComp comp = new GpsComp();
  61 + for (String nbbm : keys) {
  62 + Collections.sort(listMap.get(nbbm), comp);
  63 + threadPool.submit(new RecoveryThread(listMap.get(nbbm), count));
  64 + }
  65 +
  66 + try {
  67 + count.await();
  68 + run = false;
  69 + logger.info("数据恢复完成....");
  70 + } catch (InterruptedException e) {
  71 + logger.error("", e);
  72 + }
  73 + }
  74 +
  75 + /**
  76 + * 加载当天的gps数据
  77 + *
  78 + * @return
  79 + */
  80 + public List<GpsEntity> loadData(String lineCode, DateTime dateTime) {
  81 + int year = dateTime.getYear(), dayOfYear = dateTime.getDayOfYear();
  82 + String sql = String.format("select DEVICE_ID,LAT,LON,TS,SPEED_GPS,LINE_ID,SERVICE_STATE,SERVER_TS from bsth_c_gps_info_%d where days_year = ? and line_id = ?", year);
  83 + JdbcTemplate jdbcTemplate = new JdbcTemplate(DBUtils_MS.getDataSource());
  84 +
  85 + List<GpsEntity> list =
  86 + jdbcTemplate.query(sql, new Object[] { dayOfYear, Integer.parseInt(lineCode) }, new RowMapper<GpsEntity>() {
  87 + @Override
  88 + public GpsEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
  89 + GpsEntity gps = new GpsEntity();
  90 +
  91 + gps.setDeviceId(rs.getString("DEVICE_ID"));
  92 + gps.setNbbm(BasicData.deviceId2NbbmMap.get(gps.getDeviceId()));
  93 + gps.setSpeed(rs.getFloat("SPEED_GPS"));
  94 + gps.setLat(rs.getFloat("LAT"));
  95 + gps.setLon(rs.getFloat("LON"));
  96 + gps.setLineId(rs.getString("LINE_ID"));
  97 + gps.setTimestamp(rs.getLong("TS"));
  98 + gps.setUpDown((byte) getUpOrDown(rs.getLong("SERVICE_STATE")));
  99 + gps.setServerTimestamp(rs.getLong("SERVER_TS"));
  100 + gps.setState((int) getService(rs.getLong("SERVICE_STATE")));
  101 + return gps;
  102 + }
  103 + });
  104 + return list;
  105 + }
  106 +
  107 + /**
  108 + * 获取运营状态
  109 + *
  110 + * @return -1无效 0运营 1未运营
  111 + */
  112 + public static byte getService(long serviceState) {
  113 + if ((serviceState & 0x00020000) == 0x00020000 || (serviceState & 0x80000000) == 0x80000000)
  114 + return -1;
  115 + return (byte) (((serviceState & 0x02000000) == 0x02000000) ? 1 : 0);
  116 + }
  117 +
  118 + /**
  119 + * 王通 2016/6/29 9:23:24 获取车辆线路上下行
  120 + *
  121 + * @return -1无效 0上行 1下行
  122 + */
  123 + public static int getUpOrDown(long serviceState) {
  124 + if ((serviceState & 0x00020000) == 0x00020000 || (serviceState & 0x80000000) == 0x80000000
  125 + || (serviceState & 0x01000000) == 0x01000000 || (serviceState & 0x08000000) == 0x08000000)
  126 + return -1;
  127 + return (((serviceState & 0x10000000) == 0x10000000) ? 1 : 0);
  128 + }
  129 +
  130 + @Override
  131 + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  132 + gpsStateProcess = applicationContext.getBean(GpsStateProcess.class);
  133 + stationInsideProcess = applicationContext.getBean(StationInsideProcess.class);
  134 + inStationProcess = applicationContext.getBean(InStationProcess.class);
  135 + outStationProcess = applicationContext.getBean(OutStationProcess.class);
  136 + abnormalStateProcess = applicationContext.getBean(AbnormalStateProcess.class);
  137 + reverseRouteProcess = applicationContext.getBean(ReverseRouteProcess.class);
  138 + }
  139 +
  140 + public static class GpsComp implements Comparator<GpsEntity> {
  141 +
  142 + @Override
  143 + public int compare(GpsEntity g1, GpsEntity g2) {
  144 + return g1.getTimestamp().compareTo(g2.getTimestamp());
  145 + }
  146 + }
  147 +
  148 + public static class RecoveryThread implements Runnable {
  149 + List<GpsEntity> list;
  150 + CountDownLatch count;
  151 +
  152 + RecoveryThread(List<GpsEntity> list, CountDownLatch count) {
  153 + this.list = list;
  154 + this.count = count;
  155 + }
  156 +
  157 + @Override
  158 + public void run() {
  159 + try {
  160 + //循环gps恢复数据
  161 + for (GpsEntity gps : list) {
  162 + try {
  163 +
  164 + /*if(gps.getTimestamp() >= 1511569544000L)
  165 + System.out.println("aaa");*/
  166 +
  167 + if(Math.abs(gps.getTimestamp() - gps.getServerTimestamp()) > 1000 * 60 * 20)
  168 + continue;
  169 +
  170 + gpsStateProcess.process(gps);//状态处理
  171 + stationInsideProcess.process(gps);//场站内外判定
  172 + reverseRouteProcess.process(gps);//反向路由处理
  173 +
  174 + abnormalStateProcess.process(gps);//超速越界
  175 +
  176 + inStationProcess.process(gps);//进站
  177 + outStationProcess.process(gps);//出站
  178 +
  179 + GpsCacheData.putGps(gps);//历史gps缓存
  180 + } catch (Exception e) {
  181 + logger.error("", e);
  182 + }
  183 + }
  184 + } finally {
  185 + count.countDown();
  186 + }
  187 + }
  188 + }
194 } 189 }
195 \ No newline at end of file 190 \ No newline at end of file
src/main/java/com/bsth/data/schedule/DayOfSchedule.java
1 -package com.bsth.data.schedule;  
2 -  
3 -import com.alibaba.fastjson.JSON;  
4 -import com.alibaba.fastjson.JSONArray;  
5 -import com.bsth.common.Constants;  
6 -import com.bsth.common.ResponseCode;  
7 -import com.bsth.data.LineConfigData;  
8 -import com.bsth.data.gpsdata_v2.GpsRealData;  
9 -import com.bsth.data.gpsdata_v2.utils.GpsDataRecovery;  
10 -import com.bsth.data.schedule.f_a_l.FirstAndLastHandler;  
11 -import com.bsth.entity.realcontrol.LineConfig;  
12 -import com.bsth.entity.realcontrol.ScheduleRealInfo;  
13 -import com.bsth.entity.schedule.SchedulePlanInfo;  
14 -import com.bsth.repository.realcontrol.ScheduleRealInfoRepository;  
15 -import com.bsth.service.schedule.SchedulePlanInfoService;  
16 -import com.bsth.websocket.handler.SendUtils;  
17 -import com.google.common.collect.ArrayListMultimap;  
18 -import com.google.common.collect.HashMultimap;  
19 -import com.google.common.collect.ListMultimap;  
20 -import com.google.common.collect.Multimaps;  
21 -import org.apache.commons.lang3.StringUtils;  
22 -import org.joda.time.format.DateTimeFormat;  
23 -import org.joda.time.format.DateTimeFormatter;  
24 -import org.slf4j.Logger;  
25 -import org.slf4j.LoggerFactory;  
26 -import org.springframework.beans.factory.annotation.Autowired;  
27 -import org.springframework.dao.DataIntegrityViolationException;  
28 -import org.springframework.jdbc.core.BatchPreparedStatementSetter;  
29 -import org.springframework.jdbc.core.JdbcTemplate;  
30 -import org.springframework.jdbc.datasource.DataSourceTransactionManager;  
31 -import org.springframework.stereotype.Component;  
32 -import org.springframework.transaction.TransactionDefinition;  
33 -import org.springframework.transaction.TransactionStatus;  
34 -import org.springframework.transaction.support.DefaultTransactionDefinition;  
35 -  
36 -import java.sql.PreparedStatement;  
37 -import java.sql.SQLException;  
38 -import java.text.ParseException;  
39 -import java.text.SimpleDateFormat;  
40 -import java.util.*;  
41 -import java.util.concurrent.ConcurrentHashMap;  
42 -import java.util.concurrent.ConcurrentLinkedQueue;  
43 -import java.util.concurrent.ConcurrentMap;  
44 -  
45 -/**  
46 - * @author PanZhao  
47 - * @ClassName: DayOfSchedule  
48 - * @Description: TODO(当日实际排班)  
49 - * @date 2016年8月15日 上午10:16:12  
50 - */  
51 -@Component  
52 -public class DayOfSchedule {  
53 -  
54 - Logger logger = LoggerFactory.getLogger(this.getClass());  
55 -  
56 - //按线路分组的 “原始计划” 排班数据  
57 - public static Map<String, List<SchedulePlanInfo>> schedulePlanMap;  
58 -  
59 - // 按车辆索引的班次数据  
60 - private static ListMultimap<String, ScheduleRealInfo> nbbmScheduleMap;  
61 -  
62 - // 按营运公司索引的班次数据  
63 - private static ListMultimap<String, ScheduleRealInfo> gsBmScheduleMap;  
64 -  
65 - //按线路索引计划用车  
66 - private static HashMultimap<String, String> lineNbbmsMap;  
67 -  
68 - //按路牌索引班次数据 线路编码_路牌名称 ——> 班次list  
69 - private static ArrayListMultimap<String, ScheduleRealInfo> lpScheduleMap;  
70 -  
71 - // 班次主键映射  
72 - private static ConcurrentMap<Long, ScheduleRealInfo> id2SchedulMap;  
73 -  
74 - //车辆 ——> 当前执行班次  
75 - private static ConcurrentMap<String, ScheduleRealInfo> carExecutePlanMap;  
76 -  
77 - // 持久化  
78 - public static ConcurrentLinkedQueue<ScheduleRealInfo> pstBuffer;  
79 -  
80 - // 排序器  
81 - private static ScheduleComparator.FCSJ schFCSJComparator;  
82 -  
83 - private static ScheduleComparator.DFSJ schDFSJComparator;  
84 -  
85 - private static Long sch_max_id=-1L;  
86 -  
87 - @Autowired  
88 - LineConfigData lineConfigData;  
89 -  
90 - @Autowired  
91 - ScheduleRealInfoRepository schRepository;  
92 -  
93 - @Autowired  
94 - SchedulePlanInfoService schPlanService;  
95 -  
96 - @Autowired  
97 - SchAttrCalculator schAttrCalculator;  
98 -  
99 - @Autowired  
100 - SendUtils sendUtils;  
101 -  
102 - @Autowired  
103 - GpsRealData gpsRealData;  
104 -  
105 - /**  
106 - * 线路当前使用的排班的日期  
107 - */  
108 - public static Map<String, String> currSchDateMap;  
109 -  
110 - static {  
111 - nbbmScheduleMap = ArrayListMultimap.create();  
112 - nbbmScheduleMap = Multimaps.synchronizedListMultimap(nbbmScheduleMap);  
113 -  
114 - gsBmScheduleMap = ArrayListMultimap.create();  
115 - lpScheduleMap = ArrayListMultimap.create();  
116 - lineNbbmsMap = HashMultimap.create();  
117 -  
118 - id2SchedulMap = new ConcurrentHashMap<>();  
119 - pstBuffer = new ConcurrentLinkedQueue<>();  
120 - schFCSJComparator = new ScheduleComparator.FCSJ();  
121 - schDFSJComparator = new ScheduleComparator.DFSJ();  
122 - currSchDateMap = new HashMap<>();  
123 - carExecutePlanMap = new ConcurrentHashMap<>();  
124 -  
125 - schedulePlanMap = new HashMap<>();  
126 - }  
127 -  
128 - @Autowired  
129 - LineConfigData lineConfigs;  
130 -  
131 - @Autowired  
132 - GpsDataRecovery gpsDataRecovery;  
133 -  
134 - private static DateTimeFormatter fmtyyyyMMdd = DateTimeFormat.forPattern("yyyy-MM-dd"), fmtHHmm = DateTimeFormat.forPattern("HH:mm");  
135 -  
136 - //数据恢复  
137 - public void dataRecovery() {  
138 - Collection<LineConfig> confs = lineConfigs.getAll();  
139 - String lineCode, currSchDate;  
140 - for (LineConfig conf : confs) {  
141 - lineCode = conf.getLine().getLineCode();  
142 - currSchDate = calcSchDate(lineCode);  
143 - //加载班次数据  
144 - reloadSch(lineCode, currSchDate, false);  
145 - }  
146 -  
147 - //恢复gps数据  
148 - gpsDataRecovery.recovery();  
149 - }  
150 -  
151 - public Map<String, String> getCurrSchDate() {  
152 - return currSchDateMap;  
153 - }  
154 -  
155 - /**  
156 - * @Title: calcSchDateB  
157 - * @Description: TODO(计算线路当前应该使用的排班日期)  
158 - */  
159 - public String calcSchDate(String lineCode) {  
160 - Long t = System.currentTimeMillis();  
161 - LineConfig conf = lineConfigData.get(lineCode);  
162 -  
163 - // 小于当天起始运营时间,则取前一天的排班  
164 - String ct = fmtHHmm.print(t);  
165 - if(ct.compareTo(conf.getStartOpt()) < 0)  
166 - t -= 1000 * 60 * 60 * 24;  
167 -  
168 - String schDate = fmtyyyyMMdd.print(t);  
169 - return schDate;  
170 - }  
171 -  
172 - /**  
173 - * @param @param lineCode 线路编码  
174 - * @param @param schDate 班次日期 yyyy-MM-dd  
175 - * @param @param forcePlan 强制从计划调度重新抓取  
176 - * @Title: reloadSch  
177 - * @Title: reloadSch  
178 - * @Description: TODO(重新载入排班)  
179 - */  
180 - public int reloadSch(String lineCode, String schDate, boolean forcePlan) {  
181 - try {  
182 - List<ScheduleRealInfo> list;  
183 -  
184 - if (forcePlan)  
185 - removeRealSch(lineCode, schDate);  
186 - else  
187 - clearRAMData(lineCode);  
188 -  
189 - if (existRealSch(lineCode, schDate))  
190 - list = loadRealSch(lineCode, schDate);// 从实际排班表加载  
191 - else {  
192 - list = loadPlanSch(lineCode, schDate);// 从计划排班表加载  
193 - // 写入数据库  
194 - batchSave(list);  
195 - }  
196 -  
197 - //更新线路和班次日期对照  
198 - currSchDateMap.put(lineCode, schDate);  
199 - //添加到缓存  
200 - putAll(list);  
201 -  
202 - //标记首末班  
203 - FirstAndLastHandler.marks(list);  
204 -  
205 - Set<String> lps = searchAllLP(list);  
206 - for (String lp : lps) {  
207 - //计算“起点站应到”时间  
208 - schAttrCalculator.calcQdzTimePlan(lpScheduleMap.get(lineCode + "_" + lp));  
209 - }  
210 - Set<String> cars = searchAllCars(list);  
211 - for (String nbbm : cars) {  
212 - //车辆 ——> 要执行的班次对照  
213 - reCalcExecPlan(nbbm);  
214 - }  
215 -  
216 - //分组计划用车  
217 - reCalcLineNbbms();  
218 - // 页面 翻班通知  
219 - //sendUtils.shiftSchedule(lineCode);  
220 - } catch (Exception e) {  
221 - logger.error("", e);  
222 - return -1;  
223 - }  
224 -  
225 - return 0;  
226 - }  
227 -  
228 - public int reloadSch(String lineCode) {  
229 - return reloadSch(lineCode, calcSchDate(lineCode), true);  
230 - }  
231 -  
232 - /**  
233 - * @Title: searchAllCars  
234 - * @Description: TODO(搜索班次集合中的车辆)  
235 - */  
236 - private Set<String> searchAllCars(List<ScheduleRealInfo> list) {  
237 - Set<String> cars = new HashSet<>();  
238 - for (ScheduleRealInfo sch : list)  
239 - cars.add(sch.getClZbh());  
240 -  
241 - return cars;  
242 - }  
243 -  
244 - /**  
245 - * @Title: searchAllCars  
246 - * @Description: TODO(搜索班次集合中的路牌)  
247 - */  
248 - private Set<String> searchAllLP(List<ScheduleRealInfo> list) {  
249 - Set<String> lps = new HashSet<>();  
250 - for (ScheduleRealInfo sch : list)  
251 - lps.add(sch.getLpName());  
252 -  
253 - return lps;  
254 - }  
255 -  
256 - private void putAll(List<ScheduleRealInfo> list) {  
257 - for (ScheduleRealInfo sch : list)  
258 - put(sch);  
259 - }  
260 -  
261 - /**  
262 - * @param @param lineCode 线路编码  
263 - * @param @param schDate 班次日期 yyyy-MM-dd  
264 - * @Title: removeRealSch  
265 - * @Description: TODO(清除实际排班,包括数据库和内存数据)  
266 - */  
267 - public void removeRealSch(String lineCode, String schDate) throws Exception {  
268 - try {  
269 - // 清理数据库数据  
270 - schRepository.deleteByLineCodeAndDate(lineCode + "", schDate);  
271 -  
272 - // 清理内存数据  
273 - clearRAMData(lineCode + "");  
274 - } catch (Exception e) {  
275 - logger.error("removeRealSch error, " + lineCode + " -" + schDate, e);  
276 - throw e;  
277 - }  
278 - }  
279 -  
280 - /**  
281 - * @Title: clearRAMData  
282 - * @Description: TODO(清理内存数据)  
283 - */  
284 - public void clearRAMData(String lineCode) {  
285 - int count = 0;  
286 - List<ScheduleRealInfo> remList = new ArrayList<>();  
287 - Collection<ScheduleRealInfo> all = nbbmScheduleMap.values();  
288 - for (ScheduleRealInfo sch : all) {  
289 - if (sch.getXlBm().equals(lineCode))  
290 - remList.add(sch);  
291 - }  
292 -  
293 - for (ScheduleRealInfo sch : remList) {  
294 - if (null != sch) {  
295 - nbbmScheduleMap.remove(sch.getClZbh(), sch);  
296 - id2SchedulMap.remove(sch.getId());  
297 - count++;  
298 -  
299 - //清理路牌对照  
300 - lpScheduleMap.removeAll(sch.getXlBm() + "_" + sch.getLpName());  
301 -  
302 - //清除车辆 ——> 执行班次对照  
303 - carExecutePlanMap.remove(sch.getClZbh());  
304 - }  
305 - }  
306 - //清理计划排班  
307 - schedulePlanMap.remove(lineCode);  
308 -  
309 - remList.clear();  
310 - remList = null;  
311 - logger.info(lineCode + "排班清理 " + count);  
312 - }  
313 -  
314 - /**  
315 - * @Title: existRealSch  
316 - * @Description: TODO(实际排班是否已存在)  
317 - */  
318 - public boolean existRealSch(String lineCode, String schDate) {  
319 - int count = schRepository.countByLineCodeAndDate(lineCode, schDate);  
320 - return count > 0;  
321 - }  
322 -  
323 - /**  
324 - * @Title: loadRealSch  
325 - * @Description: TODO(从实际排班表加载数据)  
326 - */  
327 - public List<ScheduleRealInfo> loadRealSch(String lineCode, String schDate) {  
328 - return schRepository.findByLineCodeAndDate(lineCode, schDate);  
329 - }  
330 -  
331 - /**  
332 - * @Title: loadPlanSch  
333 - * @Description: TODO(从计划排班表加载数据)  
334 - */  
335 - public List<ScheduleRealInfo> loadPlanSch(String lineCode, String schDate) {  
336 - logger.info("从计划排班表恢复排班,lineCode: " + lineCode + ", schDate: " + schDate);  
337 - List<ScheduleRealInfo> realList = new ArrayList<>();  
338 -  
339 - try {  
340 - Map<String, Object> data = new HashMap<>();  
341 -  
342 - data.put("scheduleDate_eq", fmtyyyyMMdd.parseDateTime(schDate).toDate());  
343 - data.put("xlBm_eq", lineCode);  
344 -  
345 - // 查询计划排班  
346 - List<SchedulePlanInfo> planItr = cleanSchPlanItr(schPlanService.list(data).iterator());  
347 - //保存一份原始计划排班数据  
348 - schedulePlanMap.put(lineCode, planItr);  
349 -  
350 - // 转换为实际排班  
351 - realList = JSONArray.parseArray(JSON.toJSONString(planItr), ScheduleRealInfo.class);  
352 -  
353 - Date d = new Date();  
354 - SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");  
355 - String fcsj;  
356 - for (ScheduleRealInfo sch : realList) {  
357 - sch.setScheduleDateStr(fmtyyyyMMdd.print(sch.getScheduleDate().getTime()));  
358 - sch.setRealExecDate(sch.getScheduleDateStr());  
359 - sch.setCreateDate(d);  
360 -  
361 - if (StringUtils.isEmpty(sch.getFcsj()))  
362 - sch.setFcsj("00:00");  
363 -  
364 - if (sch.getFcsj().equals("24:00"))  
365 - sch.setFcsj("23:59");  
366 -  
367 - if (sch.getFcsj().substring(0, 2).equals("24")) {  
368 - sch.setFcsj("00" + sch.getFcsj().substring(2));  
369 - }  
370 -  
371 - fcsj = sch.getFcsj().trim();  
372 - //处理一下发车时间格式没有:号的问题  
373 - if (fcsj.indexOf(":") == -1 && fcsj.length() >= 4) {  
374 - sch.setFcsj(fcsj.substring(0, 2) + ":" + fcsj.substring(2, 4));  
375 - }  
376 -  
377 - try {  
378 - sdf.parse(sch.getFcsj());  
379 - } catch (ParseException e) {  
380 - //发车时间仍然校验不过的,直接写成00:00  
381 - sch.setFcsj("00:00");  
382 - }  
383 - sch.setDfsj(sch.getFcsj());  
384 -  
385 - // 计划终点时间  
386 - if (sch.getBcsj() != null) {  
387 - sch.setZdsj(fmtHHmm.print(fmtHHmm.parseMillis(sch.getFcsj()) + (sch.getBcsj() * 60 * 1000)));  
388 - sch.setLate(false);  
389 - }  
390 -  
391 - //售票员为空设置为""字符串  
392 - if (StringUtils.isEmpty(sch.getsGh())) {  
393 - sch.setsGh("");  
394 - sch.setsName("");  
395 - }  
396 - sch.setJhlcOrig(sch.getJhlc());  
397 - //保留备注  
398 - if (StringUtils.isNotEmpty(sch.getRemark()))  
399 - sch.setRemarks(sch.getRemark());  
400 - }  
401 - } catch (Exception e) {  
402 - logger.error("", e);  
403 - }  
404 -  
405 - return realList;  
406 - }  
407 -  
408 -  
409 - public synchronized long getId(){  
410 - if(sch_max_id==-1){  
411 - sch_max_id = schRepository.getMaxId();  
412 - if(null == sch_max_id)  
413 - sch_max_id = 3000L;//留一点空间补数据用  
414 - sch_max_id += 5;  
415 - }  
416 - else  
417 - sch_max_id ++;  
418 - return sch_max_id;  
419 - }  
420 -  
421 - /**  
422 - * @Title: batchSave  
423 - * @Description: TODO(批量入库)  
424 - */  
425 - private void batchSave(List<ScheduleRealInfo> list) {  
426 - SimpleDateFormat sdfyyyyMMdd = new SimpleDateFormat("yyyy-MM-dd");  
427 - for (ScheduleRealInfo item : list) {  
428 - item.setSpId(item.getId());// 保留原始的计划ID  
429 - item.setId(getId());// 设置ID  
430 - item.setScheduleDateStr(sdfyyyyMMdd.format(item.getScheduleDate()));  
431 - }  
432 -  
433 - //编程式事务  
434 - DataSourceTransactionManager tran = new DataSourceTransactionManager(jdbcTemplate.getDataSource());  
435 - DefaultTransactionDefinition def = new DefaultTransactionDefinition();  
436 - def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);  
437 - TransactionStatus status = tran.getTransaction(def);  
438 -  
439 - try{  
440 - final List<ScheduleRealInfo> pstList = list;  
441 - //写入  
442 - jdbcTemplate.batchUpdate("insert into bsth_c_s_sp_info_real(id,bc_type,bcs,bcsj,cl_zbh,create_date,dfsj,directive_state,fcno,fcsj,fcsj_actual,j_gh,j_name,jhlc,lp_name,qdz_code,qdz_name,real_exec_date,remarks,s_gh,s_name,schedule_date,schedule_date_str,sflj,sp_id,status,update_date,xl_bm,xl_dir,xl_name,zdsj,zdsj_actual,zdz_code,zdz_name,ccno,df_auto,fgs_bm,fgs_name,gs_bm,gs_name,online,adjust_exps,reissue,jhlc_orig,sigin_compate,drift_status,cc_service,major_station_name)" +  
443 - " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", new BatchPreparedStatementSetter() {  
444 - @Override  
445 - public void setValues(PreparedStatement ps, int i) throws SQLException {  
446 - ScheduleRealInfo sch = pstList.get(i);  
447 - ps.setLong(1, sch.getId());  
448 - ps.setString(2, sch.getBcType());  
449 - ps.setInt(3, sch.getBcs()==null?0:sch.getBcs());  
450 - ps.setInt(4, sch.getBcsj()==null?0:sch.getBcsj());  
451 - ps.setString(5, sch.getClZbh());  
452 - ps.setTimestamp(6, new java.sql.Timestamp(sch.getCreateDate().getTime()));  
453 - ps.setString(7, sch.getDfsj());  
454 - ps.setInt(8, sch.getDirectiveState());  
455 - ps.setInt(9, sch.getFcno()==null?0:sch.getFcno());  
456 - ps.setString(10, sch.getFcsj());  
457 - ps.setString(11, sch.getFcsjActual());  
458 - ps.setString(12, sch.getjGh());  
459 - ps.setString(13, sch.getjName());  
460 - ps.setDouble(14, sch.getJhlc());  
461 - ps.setString(15, sch.getLpName());  
462 - ps.setString(16, sch.getQdzCode());  
463 - ps.setString(17, sch.getQdzName());  
464 - ps.setString(18, sch.getRealExecDate());  
465 - ps.setString(19, sch.getRemarks());  
466 - ps.setString(20, sch.getsGh());  
467 - ps.setString(21, sch.getsName());  
468 - ps.setTimestamp(22, new java.sql.Timestamp(sch.getScheduleDate().getTime()));  
469 - ps.setString(23, sch.getScheduleDateStr());  
470 - ps.setBoolean(24, sch.isSflj());  
471 - ps.setLong(25, sch.getSpId());  
472 - ps.setInt(26, sch.getStatus());  
473 - ps.setTimestamp(27, new java.sql.Timestamp(sch.getUpdateDate().getTime()));  
474 - ps.setString(28, sch.getXlBm());  
475 - ps.setString(29, sch.getXlDir());  
476 - ps.setString(30, sch.getXlName());  
477 - ps.setString(31, sch.getZdsj());  
478 - ps.setString(32, sch.getZdsjActual());  
479 - ps.setString(33, sch.getZdzCode());  
480 - ps.setString(34, sch.getZdzName());  
481 - ps.setInt(35, sch.getCcno()==null?0:sch.getCcno());  
482 - ps.setBoolean(36, sch.isDfAuto());  
483 - ps.setString(37, sch.getFgsBm());  
484 - ps.setString(38, sch.getFgsName());  
485 - ps.setString(39, sch.getGsBm());  
486 - ps.setString(40, sch.getGsName());  
487 - ps.setBoolean(41, sch.isOnline());  
488 - ps.setString(42, sch.getAdjustExps());  
489 - ps.setBoolean(43, sch.isReissue());  
490 - ps.setDouble(44, sch.getJhlcOrig());  
491 - ps.setInt(45, sch.getSiginCompate());  
492 - ps.setInt(46, sch.getDriftStatus());  
493 - ps.setBoolean(47, sch.isCcService());  
494 - ps.setString(48, sch.getMajorStationName());  
495 - }  
496 -  
497 - @Override  
498 - public int getBatchSize() {  
499 - return pstList.size();  
500 - }  
501 - });  
502 -  
503 - tran.commit(status);  
504 - }catch (Exception e){  
505 - tran.rollback(status);  
506 - logger.error("real schedule batchSave error...", e);  
507 - }  
508 - // 入库  
509 - //new BatchSaveUtils<ScheduleRealInfo>().saveList(list, ScheduleRealInfo.class);  
510 - }  
511 -  
512 - public List<SchedulePlanInfo> cleanSchPlanItr(Iterator<SchedulePlanInfo> itrab) {  
513 - List<SchedulePlanInfo> list = new ArrayList<>();  
514 -  
515 - SchedulePlanInfo sp;  
516 - while (itrab.hasNext()) {  
517 - sp = itrab.next();  
518 - sp.setSchedulePlan(null);  
519 - sp.setCreateBy(null);  
520 - sp.setUpdateBy(null);  
521 - list.add(sp);  
522 - }  
523 - return list;  
524 - }  
525 -  
526 - /**  
527 - * @Title: findByLineCode  
528 - * @Description: TODO(lineCode 获取班次)  
529 - */  
530 - public List<ScheduleRealInfo> findByLineCode(String lineCode) {  
531 - List<ScheduleRealInfo> rs = new ArrayList<>();  
532 -  
533 - Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();  
534 - for (ScheduleRealInfo sch : schs) {  
535 - if (sch.getXlBm().equals(lineCode))  
536 - rs.add(sch);  
537 - }  
538 - return rs;  
539 - }  
540 -  
541 - /**  
542 - * @Title: findByLineCode  
543 - * @Description: TODO(lineList 获取班次)  
544 - */  
545 - public Map<String, Collection<ScheduleRealInfo>> findByLineCodes(List<String> lineList) {  
546 - ArrayListMultimap<String, ScheduleRealInfo> mMap = ArrayListMultimap.create();  
547 -  
548 - Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();  
549 - for (ScheduleRealInfo sch : schs) {  
550 - if (lineList.contains(sch.getXlBm())) {  
551 - mMap.put(sch.getXlBm(), sch);  
552 - }  
553 - }  
554 - return mMap.asMap();  
555 - }  
556 -  
557 - /**  
558 - * @Title: findCarByLineCode  
559 - * @Description: TODO(线路下运营的车辆)  
560 - */  
561 - public Set<String> findCarByLineCode(String lineCode) {  
562 - /*Set<String> rs = new HashSet<>();  
563 -  
564 - Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();  
565 - for (ScheduleRealInfo sch : schs) {  
566 - if (sch.getXlBm().equals(lineCode))  
567 - rs.add(sch.getClZbh());  
568 - }  
569 -*/  
570 - return lineNbbmsMap.get(lineCode);  
571 - }  
572 -  
573 - public List<ScheduleRealInfo> findByNbbm(String nbbm) {  
574 - return nbbmScheduleMap.get(nbbm);  
575 - }  
576 -  
577 - /**  
578 - * @Title: findByLineAndUpDown  
579 - * @Description: TODO(lineCode 和走向获取班次)  
580 - */  
581 - public List<ScheduleRealInfo> findByLineAndUpDown(String lineCode, Integer upDown) {  
582 - List<ScheduleRealInfo> list = findByLineCode(lineCode), rs = new ArrayList<>();  
583 -  
584 - for (ScheduleRealInfo sch : list) {  
585 - if (sch.getXlDir().equals(upDown + ""))  
586 - rs.add(sch);  
587 - }  
588 - return rs;  
589 - }  
590 -  
591 - public ScheduleRealInfo get(long id) {  
592 - return id2SchedulMap.get(id);  
593 - }  
594 -  
595 -  
596 - /**  
597 - * @Title: next  
598 - * @Description: TODO(下一个班次)  
599 - */  
600 - public ScheduleRealInfo next(ScheduleRealInfo sch) {  
601 - List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());  
602 - //排序  
603 - Collections.sort(list, schDFSJComparator);  
604 - return next(list, sch);  
605 - }  
606 -  
607 -  
608 - /**  
609 - * 下一个班次  
610 - *  
611 - * @param list 班次集合  
612 - * @param sch 当前班次  
613 - * @return  
614 - */  
615 - private ScheduleRealInfo next(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {  
616 - int outConfig = -1;  
617 - LineConfig config = lineConfigData.get(sch.getXlBm());  
618 - if (config != null)  
619 - outConfig = config.getOutConfig();  
620 -  
621 - //限定出站既出场的停车场  
622 - List<String> parks = config.findTwinsParkList();  
623 - boolean limitPark = null != parks && parks.size() > 0;  
624 - boolean flag = false;  
625 - ScheduleRealInfo next = null;  
626 - for (ScheduleRealInfo temp : list) {  
627 - if (temp.getId() == sch.getId()) {  
628 - flag = true;  
629 - continue;  
630 - }  
631 - //忽略烂班  
632 - if (temp.isDestroy())  
633 - continue;  
634 -  
635 - //出站既出场,忽略出场班次  
636 - if (outConfig == 2 && temp.getBcType().equals("out") && isEmptyMileage(temp)  
637 - && (!limitPark || parks.contains(temp.getQdzCode())))  
638 - continue;  
639 -  
640 - if (flag) {  
641 - next = temp;  
642 - break;  
643 - }  
644 - }  
645 - return next;  
646 - }  
647 -  
648 - private boolean isEmptyMileage(ScheduleRealInfo sch) {  
649 - return sch.getBcsj() == 0 || sch.getJhlcOrig().intValue() == 0;  
650 - }  
651 -  
652 - /**  
653 - * 下一个班次  
654 - *  
655 - * @param list 班次集合  
656 - * @param sch 当前班次  
657 - * @return  
658 - */  
659 - private ScheduleRealInfo next2_lp(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {  
660 - int outConfig = -1;  
661 - LineConfig config = lineConfigData.get(sch.getXlBm());  
662 - if (config != null)  
663 - outConfig = config.getOutConfig();  
664 -  
665 - boolean flag = false;  
666 - ScheduleRealInfo next = null;  
667 - for (ScheduleRealInfo temp : list) {  
668 - if (temp.getId() == sch.getId()) {  
669 - flag = true;  
670 - continue;  
671 - }  
672 -  
673 - if (flag) {  
674 - next = temp;  
675 - break;  
676 - }  
677 - }  
678 - return next;  
679 - }  
680 -  
681 - private ScheduleRealInfo next3_lp(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {  
682 - int outConfig = -1;  
683 - LineConfig config = lineConfigData.get(sch.getXlBm());  
684 - if (config != null)  
685 - outConfig = config.getOutConfig();  
686 -  
687 - //限定出站既出场的停车场  
688 - List<String> parks = config.findTwinsParkList();  
689 - boolean limitPark = null != parks && parks.size() > 0;  
690 - boolean flag = false;  
691 - ScheduleRealInfo next = null;  
692 - for (ScheduleRealInfo temp : list) {  
693 - if (temp.getId() == sch.getId()) {  
694 - flag = true;  
695 - continue;  
696 - }  
697 -  
698 - //出站既出场,忽略出场班次  
699 - if (outConfig == 2 && temp.getBcType().equals("out") && isEmptyMileage(temp)  
700 - && (!limitPark || parks.contains(temp.getQdzCode())))  
701 - continue;  
702 -  
703 - if (flag) {  
704 - next = temp;  
705 - break;  
706 - }  
707 - }  
708 - return next;  
709 - }  
710 -  
711 - /**  
712 - * 上一个班次  
713 - *  
714 - * @param sch  
715 - * @return  
716 - */  
717 - public ScheduleRealInfo prev(ScheduleRealInfo sch) {  
718 - List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());  
719 -  
720 - //boolean flag = false;  
721 - ScheduleRealInfo prev = null;  
722 - int size = list.size();  
723 -  
724 - for (int i = 0; i < size; i++) {  
725 - if (list.get(i).isDestroy())  
726 - continue;  
727 -  
728 - if (list.get(i).getId().equals(sch.getId())) {  
729 - return prev;  
730 - }  
731 - prev = list.get(i);  
732 - }  
733 - return prev;  
734 - }  
735 -  
736 - /**  
737 - * 是否是首班出场  
738 - *  
739 - * @param sch  
740 - * @return  
741 - */  
742 - public boolean isFirstOut(ScheduleRealInfo sch) {  
743 - List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());  
744 - try {  
745 - if (list.get(0) == sch && sch.getBcType().equals("out"))  
746 - return true;  
747 - } catch (IndexOutOfBoundsException e) {  
748 - logger.error("小小的数组越界,无伤大雅!");  
749 - }  
750 - return false;  
751 - }  
752 -  
753 - public void put(ScheduleRealInfo sch) {  
754 - schAttrCalculator  
755 - .calcRealDate(sch)  
756 - .calcAllTimeByFcsj(sch);  
757 -  
758 - nbbmScheduleMap.put(sch.getClZbh(), sch);  
759 -  
760 - //主键索引  
761 - id2SchedulMap.put(sch.getId(), sch);  
762 - //路牌对照表  
763 - addLPMapp(sch);  
764 -  
765 - //跨24点的,再save一次  
766 - if (!sch.getRealExecDate().equals(sch.getScheduleDateStr()))  
767 - save(sch);  
768 - }  
769 -  
770 - public void addLPMapp(ScheduleRealInfo sch) {  
771 - lpScheduleMap.put(sch.getXlBm() + "_" + sch.getLpName(), sch);  
772 - }  
773 -  
774 - public void delete(ScheduleRealInfo sch) {  
775 - if (!sch.isSflj())  
776 - return;  
777 -  
778 - nbbmScheduleMap.remove(sch.getClZbh(), sch);  
779 - id2SchedulMap.remove(sch.getId());  
780 - lpScheduleMap.remove(sch.getXlBm() + "_" + sch.getLpName(), sch);  
781 -  
782 - //如果正在执行该班次  
783 - if (carExecutePlanMap.get(sch.getClZbh()) == sch) {  
784 - //重新计算车辆当前执行班次  
785 - reCalcExecPlan(sch.getClZbh());  
786 - }  
787 - }  
788 -  
789 - public List<ScheduleRealInfo> updateQdzTimePlan(String lpName) {  
790 - List<ScheduleRealInfo> list = lpScheduleMap.get(lpName);  
791 - Collections.sort(list, schFCSJComparator);  
792 - return schAttrCalculator.updateQdzTimePlan(list);  
793 - }  
794 -  
795 - public List<ScheduleRealInfo> updateQdzTimePlan(ScheduleRealInfo sch) {  
796 - return updateQdzTimePlan(sch.getXlBm() + "_" + sch.getLpName());  
797 - }  
798 -  
799 - /**  
800 - * @Title: doneSum  
801 - * @Description: TODO(已完成班次总数)  
802 - */  
803 - public int doneSum(String clZbh) {  
804 - List<ScheduleRealInfo> list = nbbmScheduleMap.get(clZbh);  
805 - int rs = 0;  
806 -  
807 - for (ScheduleRealInfo sch : list) {  
808 - if (sch.getStatus() == 2 && !sch.isDestroy())  
809 - rs++;  
810 - }  
811 - return rs;  
812 - }  
813 -  
814 - public void save(ScheduleRealInfo sch) {  
815 - sch.setUpdateDate(new Date());  
816 - pstBuffer.add(sch);  
817 - }  
818 -  
819 -  
820 - /**  
821 - * @Title: nextByBcType  
822 - * @Description: TODO(获取下一个指定班次类型的班次)  
823 - */  
824 - public ScheduleRealInfo nextByBcType(String nbbm, String bcType) {  
825 - List<ScheduleRealInfo> list = findByBcType(nbbm, bcType);  
826 -  
827 - Collections.sort(list, schFCSJComparator);  
828 - ScheduleRealInfo sch = null;  
829 - for (ScheduleRealInfo temp : list) {  
830 - if (temp.getFcsjActual() == null)  
831 - sch = temp;  
832 - }  
833 -  
834 - return sch;  
835 - }  
836 -  
837 -  
838 - /**  
839 - * 搜索离当前时间最近的一个指定类型的班次  
840 - *  
841 - * @param nbbm  
842 - * @param bcType  
843 - * @return  
844 - */  
845 - public ScheduleRealInfo searchNearByBcType(String nbbm, String bcType) {  
846 - List<ScheduleRealInfo> list = findByBcType(nbbm, bcType);  
847 - Collections.sort(list, schFCSJComparator);  
848 -  
849 - long t = System.currentTimeMillis();  
850 - int distance = -1, diff;  
851 -  
852 - ScheduleRealInfo sch = null;  
853 - for (ScheduleRealInfo temp : list) {  
854 - diff = (int) Math.abs(temp.getDfsjT() - t);  
855 - if (diff < distance || distance == -1) {  
856 - sch = temp;  
857 - distance = diff;  
858 - }  
859 - }  
860 - return sch;  
861 - }  
862 -  
863 - public List<ScheduleRealInfo> findByBcType(String nbbm, String bcType) {  
864 - List<ScheduleRealInfo> all = nbbmScheduleMap.get(nbbm), outList = new ArrayList<>();  
865 -  
866 - for (ScheduleRealInfo sch : all) {  
867 - if (sch.getBcType().equals(bcType))  
868 - outList.add(sch);  
869 - }  
870 - return outList;  
871 - }  
872 -  
873 - public Collection<ScheduleRealInfo> findAll() {  
874 - return nbbmScheduleMap.values();  
875 - }  
876 -  
877 - public Collection<ScheduleRealInfo> findAllByLpContainer() {  
878 - return lpScheduleMap.values();  
879 - }  
880 -  
881 - public Collection<ScheduleRealInfo> findAllByIdContainer() {  
882 - return id2SchedulMap.values();  
883 - }  
884 -  
885 - public int getPstSize() {  
886 - return pstBuffer.size();  
887 - }  
888 -  
889 - public boolean addExecPlan(ScheduleRealInfo sch) {  
890 - ScheduleRealInfo oldExec = executeCurr(sch.getClZbh());  
891 - if (sch != null){  
892 - if(sch.getStatus()==2)  
893 - reCalcExecPlan(sch.getClZbh());  
894 - else  
895 - carExecutePlanMap.put(sch.getClZbh(), sch);  
896 - }  
897 - else  
898 - carExecutePlanMap.remove(sch.getClZbh());  
899 -  
900 - return executeCurr(sch.getClZbh()) != oldExec;  
901 - }  
902 -  
903 - public void removeExecPlan(String clzbh) {  
904 - carExecutePlanMap.remove(clzbh);  
905 - }  
906 -  
907 - public Map<String, ScheduleRealInfo> execPlanMap() {  
908 - return carExecutePlanMap;  
909 - }  
910 -  
911 - /**  
912 - * 车辆当前执行的班次  
913 - *  
914 - * @param nbbm  
915 - * @return  
916 - */  
917 - public ScheduleRealInfo executeCurr(String nbbm) {  
918 - if(StringUtils.isEmpty(nbbm))  
919 - return null;  
920 - return carExecutePlanMap.get(nbbm);  
921 - }  
922 -  
923 - /**  
924 - * @param @param sch  
925 - * @param @param newClZbh 新的车辆自编号  
926 - * @Title: changeCar  
927 - * @Description: TODO(班次换车) 返回有更新的班次  
928 - */  
929 - public List<ScheduleRealInfo> changeCar(ScheduleRealInfo sch, String newClZbh) {  
930 - List<ScheduleRealInfo> ups = new ArrayList<>();  
931 -  
932 - String oldClZbh = sch.getClZbh();  
933 - //变更相关映射信息  
934 - nbbmScheduleMap.remove(sch.getClZbh(), sch);  
935 -  
936 - sch.setClZbh(newClZbh);  
937 - if (!nbbmScheduleMap.containsEntry(newClZbh, sch)) {  
938 - nbbmScheduleMap.put(newClZbh, sch);  
939 - }  
940 -  
941 - //重新计算车辆当前执行班次  
942 - reCalcExecPlan(newClZbh);  
943 - reCalcExecPlan(oldClZbh);  
944 - //重新分组计划用车  
945 - reCalcLineNbbms();  
946 - return ups;  
947 - }  
948 -  
949 - public void removeNbbm2SchMapp(ScheduleRealInfo sch) {  
950 - nbbmScheduleMap.remove(sch.getClZbh(), sch);  
951 - }  
952 -  
953 - public void addNbbm2SchMapp(ScheduleRealInfo sch) {  
954 - nbbmScheduleMap.put(sch.getClZbh(), sch);  
955 - }  
956 -  
957 - public void reCalcExecPlan(String nbbm) {  
958 - List<ScheduleRealInfo> list = nbbmScheduleMap.get(nbbm);  
959 - Collections.sort(list, schDFSJComparator);  
960 -  
961 - ScheduleRealInfo sch = schAttrCalculator.calcCurrentExecSch(list);  
962 - if(null != sch)  
963 - carExecutePlanMap.put(nbbm, sch);  
964 - else  
965 - carExecutePlanMap.remove(nbbm);  
966 - }  
967 -  
968 - /**  
969 - * 空驶任务?  
970 - * 出场、进场、直放、两点间空驶  
971 - * @param sch  
972 - * @return  
973 - */  
974 - public static boolean emptyService(ScheduleRealInfo sch){  
975 - String type = sch.getBcType();  
976 - return type.equals("out") || type.equals("in") || type.equals("venting") || type.equals("ldks");  
977 - }  
978 -  
979 - @Autowired  
980 - JdbcTemplate jdbcTemplate;  
981 -  
982 - /**  
983 - * 删除实际排班  
984 - *  
985 - * @param lineCode  
986 - * @return  
987 - */  
988 - public Map<String, Object> deleteRealSchedule(String lineCode) {  
989 - Map<String, Object> rs = new HashMap<>();  
990 -  
991 - try {  
992 - String rq = currSchDateMap.get(lineCode);  
993 - if (StringUtils.isNotEmpty(rq)) {  
994 - List<ScheduleRealInfo> all = findByLineCode(lineCode);  
995 -  
996 - if(null != all && all.size() > 0){  
997 - //解除gps 和班次之间的关联  
998 - List<ScheduleRealInfo> unions = calcUnion(all, carExecutePlanMap.values());  
999 - for (ScheduleRealInfo sch : unions) {  
1000 - removeExecPlan(sch.getClZbh());  
1001 - }  
1002 - //解除调度指令和班次的外键约束  
1003 - StringBuilder inStr = new StringBuilder("(");  
1004 - for (ScheduleRealInfo sch : all) {  
1005 - inStr.append(sch.getId() + ",");  
1006 - }  
1007 - inStr.deleteCharAt(inStr.length() - 1).append(")");  
1008 - jdbcTemplate.update(Constants.MULTI_REMOVE_DIRECTIVE_SCH_FK + " " + inStr.toString());  
1009 - }  
1010 -  
1011 - //删除班次数据  
1012 - removeRealSch(lineCode, rq);  
1013 -  
1014 - }  
1015 - rs.put("status", ResponseCode.SUCCESS);  
1016 - } catch (Exception e) {  
1017 - logger.error("", e);  
1018 - rs.put("status", ResponseCode.ERROR);  
1019 - if (e instanceof DataIntegrityViolationException)  
1020 - rs.put("msg", "失败,违反数据约束!!");  
1021 - else  
1022 - rs.put("msg", e.getMessage());  
1023 - }  
1024 -  
1025 - return rs;  
1026 - }  
1027 -  
1028 - /**  
1029 - * 计算并集  
1030 - *  
1031 - * @param all  
1032 - * @param sub  
1033 - * @return  
1034 - */  
1035 - public List<ScheduleRealInfo> calcUnion(Collection<ScheduleRealInfo> c1, Collection<ScheduleRealInfo> c2) {  
1036 - List<ScheduleRealInfo> rs = new ArrayList<>();  
1037 -  
1038 - for (ScheduleRealInfo sch : c1) {  
1039 - if (c2.contains(sch)) {  
1040 - rs.add(sch);  
1041 - }  
1042 - }  
1043 - return rs;  
1044 - }  
1045 -  
1046 - /**  
1047 - * 覆盖一辆车的所有班次  
1048 - *  
1049 - * @param nbbm  
1050 - * @param sets  
1051 - */  
1052 - public void replaceByNbbm(String nbbm, Collection<ScheduleRealInfo> sets) {  
1053 - nbbmScheduleMap.removeAll(nbbm);  
1054 - nbbmScheduleMap.putAll(nbbm, sets);  
1055 - }  
1056 -  
1057 - /**  
1058 - * 获取该班次所在路牌的下一个班次  
1059 - *  
1060 - * @param sch  
1061 - * @return  
1062 - */  
1063 - public ScheduleRealInfo nextByLp(ScheduleRealInfo sch) {  
1064 - List<ScheduleRealInfo> list = lpScheduleMap.get(sch.getXlBm() + "_" + sch.getLpName());  
1065 - Collections.sort(list, schFCSJComparator);  
1066 - return next3_lp(list, sch);  
1067 - }  
1068 -  
1069 - /**  
1070 - * 获取该班次所在路牌的下一个班次,不考虑场既是站  
1071 - *  
1072 - * @param sch  
1073 - * @return  
1074 - */  
1075 - public ScheduleRealInfo nextByLp2(ScheduleRealInfo sch) {  
1076 - List<ScheduleRealInfo> list = lpScheduleMap.get(sch.getXlBm() + "_" + sch.getLpName());  
1077 - Collections.sort(list, schFCSJComparator);  
1078 - return next2_lp(list, sch);  
1079 - }  
1080 -  
1081 - public ArrayListMultimap<String, ScheduleRealInfo> getLpScheduleMap() {  
1082 - return lpScheduleMap;  
1083 - }  
1084 -  
1085 - /**  
1086 - * 重新全量计算路牌下的班次关联性  
1087 - * 临时性的函数  
1088 - */  
1089 - public void _test_reCalcLpSch() {  
1090 - Map<String ,Collection<ScheduleRealInfo>> map = lpScheduleMap.asMap();  
1091 - Set<String> ks = map.keySet();  
1092 - for(String k : ks){  
1093 - schAttrCalculator.calcQdzTimePlan(new ArrayList<ScheduleRealInfo>(map.get(k)));  
1094 - }  
1095 - }  
1096 -  
1097 - public int dbCount(String lineCode, String currSchDate) {  
1098 - int count = -1;  
1099 -  
1100 - try{  
1101 - count = jdbcTemplate.queryForObject("select count(*) from bsth_c_s_sp_info_real where schedule_date='"+currSchDate+"' and xl_bm='"+lineCode+"'", java.lang.Integer.class);  
1102 -  
1103 - }catch (Exception e){  
1104 - logger.error("", e);  
1105 - }  
1106 - return count;  
1107 - }  
1108 -  
1109 - /**  
1110 - * 重新计算ID对照map  
1111 - */  
1112 - public int reCalcIdMaps(){  
1113 - Collection<ScheduleRealInfo> all = findAll();  
1114 - ConcurrentMap<Long, ScheduleRealInfo> id2SchedulMapCopy = new ConcurrentHashMap<>();  
1115 -  
1116 - for(ScheduleRealInfo sch : all){  
1117 - id2SchedulMapCopy.put(sch.getId(), sch);  
1118 - }  
1119 -  
1120 - id2SchedulMap = id2SchedulMapCopy;  
1121 -  
1122 - return id2SchedulMap.size();  
1123 - }  
1124 -  
1125 - /**  
1126 - * 重新计算线路计划用车  
1127 - */  
1128 - public void reCalcLineNbbms(){  
1129 - HashMultimap<String, String> multimap = HashMultimap.create();  
1130 -  
1131 - Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();  
1132 - for (ScheduleRealInfo sch : schs) {  
1133 - multimap.put(sch.getXlBm(), sch.getClZbh());  
1134 - }  
1135 -  
1136 - lineNbbmsMap = multimap;  
1137 - }  
1138 -  
1139 - public String sizeString(){  
1140 - return id2SchedulMap.size() + "/" + nbbmScheduleMap.size();  
1141 - }  
1142 -  
1143 -  
1144 - /**  
1145 - * 按公司编码分组数据  
1146 - */  
1147 - public void groupByGsbm(){  
1148 - Collection<ScheduleRealInfo> all = findAll();  
1149 - ListMultimap<String, ScheduleRealInfo> gsBmMaps = ArrayListMultimap.create();  
1150 -  
1151 - for(ScheduleRealInfo sch : all){  
1152 - gsBmMaps.put(sch.getGsBm(), sch);  
1153 - }  
1154 -  
1155 - if(gsBmMaps.size() > 0){  
1156 - gsBmScheduleMap = null;  
1157 - gsBmScheduleMap = gsBmMaps;  
1158 - }  
1159 - }  
1160 -  
1161 - public Collection<ScheduleRealInfo> findByGsbm(String gsbm){  
1162 - return gsBmScheduleMap.get(gsbm);  
1163 - } 1 +package com.bsth.data.schedule;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.JSONArray;
  5 +import com.bsth.common.Constants;
  6 +import com.bsth.common.ResponseCode;
  7 +import com.bsth.data.LineConfigData;
  8 +import com.bsth.data.gpsdata_v2.GpsRealData;
  9 +import com.bsth.data.gpsdata_v2.utils.GpsDataRecovery;
  10 +import com.bsth.data.schedule.f_a_l.FirstAndLastHandler;
  11 +import com.bsth.entity.realcontrol.LineConfig;
  12 +import com.bsth.entity.realcontrol.ScheduleRealInfo;
  13 +import com.bsth.entity.schedule.SchedulePlanInfo;
  14 +import com.bsth.repository.realcontrol.ScheduleRealInfoRepository;
  15 +import com.bsth.service.schedule.SchedulePlanInfoService;
  16 +import com.bsth.websocket.handler.SendUtils;
  17 +import com.google.common.collect.ArrayListMultimap;
  18 +import com.google.common.collect.HashMultimap;
  19 +import com.google.common.collect.ListMultimap;
  20 +import com.google.common.collect.Multimaps;
  21 +import org.apache.commons.lang3.StringUtils;
  22 +import org.joda.time.DateTime;
  23 +import org.joda.time.format.DateTimeFormat;
  24 +import org.joda.time.format.DateTimeFormatter;
  25 +import org.slf4j.Logger;
  26 +import org.slf4j.LoggerFactory;
  27 +import org.springframework.beans.factory.annotation.Autowired;
  28 +import org.springframework.dao.DataIntegrityViolationException;
  29 +import org.springframework.jdbc.core.BatchPreparedStatementSetter;
  30 +import org.springframework.jdbc.core.JdbcTemplate;
  31 +import org.springframework.jdbc.datasource.DataSourceTransactionManager;
  32 +import org.springframework.scheduling.annotation.EnableScheduling;
  33 +import org.springframework.scheduling.annotation.Scheduled;
  34 +import org.springframework.stereotype.Component;
  35 +import org.springframework.transaction.TransactionDefinition;
  36 +import org.springframework.transaction.TransactionStatus;
  37 +import org.springframework.transaction.support.DefaultTransactionDefinition;
  38 +
  39 +import java.sql.PreparedStatement;
  40 +import java.sql.SQLException;
  41 +import java.text.ParseException;
  42 +import java.text.SimpleDateFormat;
  43 +import java.util.*;
  44 +import java.util.concurrent.ConcurrentHashMap;
  45 +import java.util.concurrent.ConcurrentLinkedQueue;
  46 +import java.util.concurrent.ConcurrentMap;
  47 +
  48 +/**
  49 + * @author PanZhao
  50 + * @ClassName: DayOfSchedule
  51 + * @Description: TODO(当日实际排班)
  52 + * @date 2016年8月15日 上午10:16:12
  53 + */
  54 +@Component
  55 +@EnableScheduling
  56 +public class DayOfSchedule {
  57 +
  58 + Logger logger = LoggerFactory.getLogger(this.getClass());
  59 +
  60 + //按线路分组的 “原始计划” 排班数据
  61 + public static Map<String, List<SchedulePlanInfo>> schedulePlanMap;
  62 +
  63 + // 按车辆索引的班次数据
  64 + private static ListMultimap<String, ScheduleRealInfo> nbbmScheduleMap;
  65 +
  66 + // 按营运公司索引的班次数据
  67 + private static ListMultimap<String, ScheduleRealInfo> gsBmScheduleMap;
  68 +
  69 + //按线路索引计划用车
  70 + private static HashMultimap<String, String> lineNbbmsMap;
  71 +
  72 + //按路牌索引班次数据 线路编码_路牌名称 ——> 班次list
  73 + private static ArrayListMultimap<String, ScheduleRealInfo> lpScheduleMap;
  74 +
  75 + // 班次主键映射
  76 + private static ConcurrentMap<Long, ScheduleRealInfo> id2SchedulMap;
  77 +
  78 + //车辆 ——> 当前执行班次
  79 + private static ConcurrentMap<String, ScheduleRealInfo> carExecutePlanMap;
  80 +
  81 + // 持久化
  82 + public static ConcurrentLinkedQueue<ScheduleRealInfo> pstBuffer;
  83 +
  84 + // 排序器
  85 + private static ScheduleComparator.FCSJ schFCSJComparator;
  86 +
  87 + private static ScheduleComparator.DFSJ schDFSJComparator;
  88 +
  89 + private static Long sch_max_id=-1L;
  90 +
  91 + @Autowired
  92 + LineConfigData lineConfigData;
  93 +
  94 + @Autowired
  95 + ScheduleRealInfoRepository schRepository;
  96 +
  97 + @Autowired
  98 + SchedulePlanInfoService schPlanService;
  99 +
  100 + @Autowired
  101 + SchAttrCalculator schAttrCalculator;
  102 +
  103 + @Autowired
  104 + SendUtils sendUtils;
  105 +
  106 + @Autowired
  107 + GpsRealData gpsRealData;
  108 +
  109 + /**
  110 + * 线路当前使用的排班的日期
  111 + */
  112 + public static Map<String, String> currSchDateMap;
  113 +
  114 + static {
  115 + nbbmScheduleMap = ArrayListMultimap.create();
  116 + nbbmScheduleMap = Multimaps.synchronizedListMultimap(nbbmScheduleMap);
  117 +
  118 + gsBmScheduleMap = ArrayListMultimap.create();
  119 + lpScheduleMap = ArrayListMultimap.create();
  120 + lineNbbmsMap = HashMultimap.create();
  121 +
  122 + id2SchedulMap = new ConcurrentHashMap<>();
  123 + pstBuffer = new ConcurrentLinkedQueue<>();
  124 + schFCSJComparator = new ScheduleComparator.FCSJ();
  125 + schDFSJComparator = new ScheduleComparator.DFSJ();
  126 + currSchDateMap = new HashMap<>();
  127 + carExecutePlanMap = new ConcurrentHashMap<>();
  128 +
  129 + schedulePlanMap = new HashMap<>();
  130 + }
  131 +
  132 + @Autowired
  133 + LineConfigData lineConfigs;
  134 +
  135 + @Autowired
  136 + GpsDataRecovery gpsDataRecovery;
  137 +
  138 + private static DateTimeFormatter fmtyyyyMMdd = DateTimeFormat.forPattern("yyyy-MM-dd"), fmtHHmm = DateTimeFormat.forPattern("HH:mm");
  139 +
  140 + //数据恢复
  141 + public void dataRecovery() {
  142 + Collection<LineConfig> confs = lineConfigs.getAll();
  143 + String lineCode, currSchDate;
  144 + for (LineConfig conf : confs) {
  145 + lineCode = conf.getLine().getLineCode();
  146 + currSchDate = calcSchDate(lineCode);
  147 + //加载班次数据
  148 + reloadSch(lineCode, currSchDate, false);
  149 + //恢复gps数据
  150 + gpsDataRecovery.recovery(lineCode, fmtyyyyMMdd.parseDateTime(currSchDate));
  151 + }
  152 +
  153 + }
  154 +
  155 + /**
  156 + * 自动执行的班次在翻班前40分钟内根据历史GPS生成实际班次的发车和到达信息
  157 + */
  158 + @Scheduled(cron = "0 0/10 * * * ?")
  159 + public void autoExecLineRecovery() {
  160 + Collection<LineConfig> confs = lineConfigs.getAll();
  161 + String lineCode, currSchDate;
  162 + DateTime now = DateTime.now();
  163 + for (LineConfig conf : confs) {
  164 + DateTime refreshTime = fmtHHmm.parseDateTime(conf.getStartOpt());
  165 + long dval = refreshTime.getMillis() - now.getMillis();
  166 + if (conf.isAutoExec() && dval > 0 && dval < 2400000) {
  167 + lineCode = conf.getLine().getLineCode();
  168 + currSchDate = calcSchDate(lineCode);
  169 + deleteRealSchedule(lineCode);
  170 + //加载班次数据
  171 + reloadSch(lineCode, currSchDate, false);
  172 + //恢复gps数据
  173 + gpsDataRecovery.recovery(lineCode, fmtyyyyMMdd.parseDateTime(currSchDate));
  174 + }
  175 + }
  176 + }
  177 +
  178 + public Map<String, String> getCurrSchDate() {
  179 + return currSchDateMap;
  180 + }
  181 +
  182 + /**
  183 + * @Title: calcSchDateB
  184 + * @Description: TODO(计算线路当前应该使用的排班日期)
  185 + */
  186 + public String calcSchDate(String lineCode) {
  187 + Long t = System.currentTimeMillis();
  188 + LineConfig conf = lineConfigData.get(lineCode);
  189 +
  190 + // 小于当天起始运营时间,则取前一天的排班
  191 + String ct = fmtHHmm.print(t);
  192 + if(ct.compareTo(conf.getStartOpt()) < 0)
  193 + t -= 1000 * 60 * 60 * 24;
  194 +
  195 + String schDate = fmtyyyyMMdd.print(t);
  196 + return schDate;
  197 + }
  198 +
  199 + /**
  200 + * @param @param lineCode 线路编码
  201 + * @param @param schDate 班次日期 yyyy-MM-dd
  202 + * @param @param forcePlan 强制从计划调度重新抓取
  203 + * @Title: reloadSch
  204 + * @Title: reloadSch
  205 + * @Description: TODO(重新载入排班)
  206 + */
  207 + public int reloadSch(String lineCode, String schDate, boolean forcePlan) {
  208 + try {
  209 + List<ScheduleRealInfo> list;
  210 +
  211 + if (forcePlan)
  212 + removeRealSch(lineCode, schDate);
  213 + else
  214 + clearRAMData(lineCode);
  215 +
  216 + if (existRealSch(lineCode, schDate))
  217 + list = loadRealSch(lineCode, schDate);// 从实际排班表加载
  218 + else {
  219 + list = loadPlanSch(lineCode, schDate);// 从计划排班表加载
  220 + // 写入数据库
  221 + batchSave(list);
  222 + }
  223 +
  224 + //更新线路和班次日期对照
  225 + currSchDateMap.put(lineCode, schDate);
  226 + //添加到缓存
  227 + putAll(list);
  228 +
  229 + //标记首末班
  230 + FirstAndLastHandler.marks(list);
  231 +
  232 + Set<String> lps = searchAllLP(list);
  233 + for (String lp : lps) {
  234 + //计算“起点站应到”时间
  235 + schAttrCalculator.calcQdzTimePlan(lpScheduleMap.get(lineCode + "_" + lp));
  236 + }
  237 + Set<String> cars = searchAllCars(list);
  238 + for (String nbbm : cars) {
  239 + //车辆 ——> 要执行的班次对照
  240 + reCalcExecPlan(nbbm);
  241 + }
  242 +
  243 + //分组计划用车
  244 + reCalcLineNbbms();
  245 + // 页面 翻班通知
  246 + //sendUtils.shiftSchedule(lineCode);
  247 + } catch (Exception e) {
  248 + logger.error("", e);
  249 + return -1;
  250 + }
  251 +
  252 + return 0;
  253 + }
  254 +
  255 + public int reloadSch(String lineCode) {
  256 + return reloadSch(lineCode, calcSchDate(lineCode), true);
  257 + }
  258 +
  259 + /**
  260 + * @Title: searchAllCars
  261 + * @Description: TODO(搜索班次集合中的车辆)
  262 + */
  263 + private Set<String> searchAllCars(List<ScheduleRealInfo> list) {
  264 + Set<String> cars = new HashSet<>();
  265 + for (ScheduleRealInfo sch : list)
  266 + cars.add(sch.getClZbh());
  267 +
  268 + return cars;
  269 + }
  270 +
  271 + /**
  272 + * @Title: searchAllCars
  273 + * @Description: TODO(搜索班次集合中的路牌)
  274 + */
  275 + private Set<String> searchAllLP(List<ScheduleRealInfo> list) {
  276 + Set<String> lps = new HashSet<>();
  277 + for (ScheduleRealInfo sch : list)
  278 + lps.add(sch.getLpName());
  279 +
  280 + return lps;
  281 + }
  282 +
  283 + private void putAll(List<ScheduleRealInfo> list) {
  284 + for (ScheduleRealInfo sch : list)
  285 + put(sch);
  286 + }
  287 +
  288 + /**
  289 + * @param @param lineCode 线路编码
  290 + * @param @param schDate 班次日期 yyyy-MM-dd
  291 + * @Title: removeRealSch
  292 + * @Description: TODO(清除实际排班,包括数据库和内存数据)
  293 + */
  294 + public void removeRealSch(String lineCode, String schDate) throws Exception {
  295 + try {
  296 + // 清理数据库数据
  297 + schRepository.deleteByLineCodeAndDate(lineCode + "", schDate);
  298 +
  299 + // 清理内存数据
  300 + clearRAMData(lineCode + "");
  301 + } catch (Exception e) {
  302 + logger.error("removeRealSch error, " + lineCode + " -" + schDate, e);
  303 + throw e;
  304 + }
  305 + }
  306 +
  307 + /**
  308 + * @Title: clearRAMData
  309 + * @Description: TODO(清理内存数据)
  310 + */
  311 + public void clearRAMData(String lineCode) {
  312 + int count = 0;
  313 + List<ScheduleRealInfo> remList = new ArrayList<>();
  314 + Collection<ScheduleRealInfo> all = nbbmScheduleMap.values();
  315 + for (ScheduleRealInfo sch : all) {
  316 + if (sch.getXlBm().equals(lineCode))
  317 + remList.add(sch);
  318 + }
  319 +
  320 + for (ScheduleRealInfo sch : remList) {
  321 + if (null != sch) {
  322 + nbbmScheduleMap.remove(sch.getClZbh(), sch);
  323 + id2SchedulMap.remove(sch.getId());
  324 + count++;
  325 +
  326 + //清理路牌对照
  327 + lpScheduleMap.removeAll(sch.getXlBm() + "_" + sch.getLpName());
  328 +
  329 + //清除车辆 ——> 执行班次对照
  330 + carExecutePlanMap.remove(sch.getClZbh());
  331 + }
  332 + }
  333 + //清理计划排班
  334 + schedulePlanMap.remove(lineCode);
  335 +
  336 + remList.clear();
  337 + remList = null;
  338 + logger.info(lineCode + "排班清理 " + count);
  339 + }
  340 +
  341 + /**
  342 + * @Title: existRealSch
  343 + * @Description: TODO(实际排班是否已存在)
  344 + */
  345 + public boolean existRealSch(String lineCode, String schDate) {
  346 + int count = schRepository.countByLineCodeAndDate(lineCode, schDate);
  347 + return count > 0;
  348 + }
  349 +
  350 + /**
  351 + * @Title: loadRealSch
  352 + * @Description: TODO(从实际排班表加载数据)
  353 + */
  354 + public List<ScheduleRealInfo> loadRealSch(String lineCode, String schDate) {
  355 + return schRepository.findByLineCodeAndDate(lineCode, schDate);
  356 + }
  357 +
  358 + /**
  359 + * @Title: loadPlanSch
  360 + * @Description: TODO(从计划排班表加载数据)
  361 + */
  362 + public List<ScheduleRealInfo> loadPlanSch(String lineCode, String schDate) {
  363 + logger.info("从计划排班表恢复排班,lineCode: " + lineCode + ", schDate: " + schDate);
  364 + List<ScheduleRealInfo> realList = new ArrayList<>();
  365 +
  366 + try {
  367 + Map<String, Object> data = new HashMap<>();
  368 +
  369 + data.put("scheduleDate_eq", fmtyyyyMMdd.parseDateTime(schDate).toDate());
  370 + data.put("xlBm_eq", lineCode);
  371 +
  372 + // 查询计划排班
  373 + List<SchedulePlanInfo> planItr = cleanSchPlanItr(schPlanService.list(data).iterator());
  374 + //保存一份原始计划排班数据
  375 + schedulePlanMap.put(lineCode, planItr);
  376 +
  377 + // 转换为实际排班
  378 + realList = JSONArray.parseArray(JSON.toJSONString(planItr), ScheduleRealInfo.class);
  379 +
  380 + Date d = new Date();
  381 + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
  382 + String fcsj;
  383 + for (ScheduleRealInfo sch : realList) {
  384 + sch.setScheduleDateStr(fmtyyyyMMdd.print(sch.getScheduleDate().getTime()));
  385 + sch.setRealExecDate(sch.getScheduleDateStr());
  386 + sch.setCreateDate(d);
  387 +
  388 + if (StringUtils.isEmpty(sch.getFcsj()))
  389 + sch.setFcsj("00:00");
  390 +
  391 + if (sch.getFcsj().equals("24:00"))
  392 + sch.setFcsj("23:59");
  393 +
  394 + if (sch.getFcsj().substring(0, 2).equals("24")) {
  395 + sch.setFcsj("00" + sch.getFcsj().substring(2));
  396 + }
  397 +
  398 + fcsj = sch.getFcsj().trim();
  399 + //处理一下发车时间格式没有:号的问题
  400 + if (fcsj.indexOf(":") == -1 && fcsj.length() >= 4) {
  401 + sch.setFcsj(fcsj.substring(0, 2) + ":" + fcsj.substring(2, 4));
  402 + }
  403 +
  404 + try {
  405 + sdf.parse(sch.getFcsj());
  406 + } catch (ParseException e) {
  407 + //发车时间仍然校验不过的,直接写成00:00
  408 + sch.setFcsj("00:00");
  409 + }
  410 + sch.setDfsj(sch.getFcsj());
  411 +
  412 + // 计划终点时间
  413 + if (sch.getBcsj() != null) {
  414 + sch.setZdsj(fmtHHmm.print(fmtHHmm.parseMillis(sch.getFcsj()) + (sch.getBcsj() * 60 * 1000)));
  415 + sch.setLate(false);
  416 + }
  417 +
  418 + //售票员为空设置为""字符串
  419 + if (StringUtils.isEmpty(sch.getsGh())) {
  420 + sch.setsGh("");
  421 + sch.setsName("");
  422 + }
  423 + sch.setJhlcOrig(sch.getJhlc());
  424 + //保留备注
  425 + if (StringUtils.isNotEmpty(sch.getRemark()))
  426 + sch.setRemarks(sch.getRemark());
  427 + }
  428 + } catch (Exception e) {
  429 + logger.error("", e);
  430 + }
  431 +
  432 + return realList;
  433 + }
  434 +
  435 +
  436 + public synchronized long getId(){
  437 + if(sch_max_id==-1){
  438 + sch_max_id = schRepository.getMaxId();
  439 + if(null == sch_max_id)
  440 + sch_max_id = 3000L;//留一点空间补数据用
  441 + sch_max_id += 5;
  442 + }
  443 + else
  444 + sch_max_id ++;
  445 + return sch_max_id;
  446 + }
  447 +
  448 + /**
  449 + * @Title: batchSave
  450 + * @Description: TODO(批量入库)
  451 + */
  452 + private void batchSave(List<ScheduleRealInfo> list) {
  453 + SimpleDateFormat sdfyyyyMMdd = new SimpleDateFormat("yyyy-MM-dd");
  454 + for (ScheduleRealInfo item : list) {
  455 + item.setSpId(item.getId());// 保留原始的计划ID
  456 + item.setId(getId());// 设置ID
  457 + item.setScheduleDateStr(sdfyyyyMMdd.format(item.getScheduleDate()));
  458 + }
  459 +
  460 + //编程式事务
  461 + DataSourceTransactionManager tran = new DataSourceTransactionManager(jdbcTemplate.getDataSource());
  462 + DefaultTransactionDefinition def = new DefaultTransactionDefinition();
  463 + def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
  464 + TransactionStatus status = tran.getTransaction(def);
  465 +
  466 + try{
  467 + final List<ScheduleRealInfo> pstList = list;
  468 + //写入
  469 + jdbcTemplate.batchUpdate("insert into bsth_c_s_sp_info_real(id,bc_type,bcs,bcsj,cl_zbh,create_date,dfsj,directive_state,fcno,fcsj,fcsj_actual,j_gh,j_name,jhlc,lp_name,qdz_code,qdz_name,real_exec_date,remarks,s_gh,s_name,schedule_date,schedule_date_str,sflj,sp_id,status,update_date,xl_bm,xl_dir,xl_name,zdsj,zdsj_actual,zdz_code,zdz_name,ccno,df_auto,fgs_bm,fgs_name,gs_bm,gs_name,online,adjust_exps,reissue,jhlc_orig,sigin_compate,drift_status,cc_service,major_station_name)" +
  470 + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", new BatchPreparedStatementSetter() {
  471 + @Override
  472 + public void setValues(PreparedStatement ps, int i) throws SQLException {
  473 + ScheduleRealInfo sch = pstList.get(i);
  474 + ps.setLong(1, sch.getId());
  475 + ps.setString(2, sch.getBcType());
  476 + ps.setInt(3, sch.getBcs()==null?0:sch.getBcs());
  477 + ps.setInt(4, sch.getBcsj()==null?0:sch.getBcsj());
  478 + ps.setString(5, sch.getClZbh());
  479 + ps.setTimestamp(6, new java.sql.Timestamp(sch.getCreateDate().getTime()));
  480 + ps.setString(7, sch.getDfsj());
  481 + ps.setInt(8, sch.getDirectiveState());
  482 + ps.setInt(9, sch.getFcno()==null?0:sch.getFcno());
  483 + ps.setString(10, sch.getFcsj());
  484 + ps.setString(11, sch.getFcsjActual());
  485 + ps.setString(12, sch.getjGh());
  486 + ps.setString(13, sch.getjName());
  487 + ps.setDouble(14, sch.getJhlc());
  488 + ps.setString(15, sch.getLpName());
  489 + ps.setString(16, sch.getQdzCode());
  490 + ps.setString(17, sch.getQdzName());
  491 + ps.setString(18, sch.getRealExecDate());
  492 + ps.setString(19, sch.getRemarks());
  493 + ps.setString(20, sch.getsGh());
  494 + ps.setString(21, sch.getsName());
  495 + ps.setTimestamp(22, new java.sql.Timestamp(sch.getScheduleDate().getTime()));
  496 + ps.setString(23, sch.getScheduleDateStr());
  497 + ps.setBoolean(24, sch.isSflj());
  498 + ps.setLong(25, sch.getSpId());
  499 + ps.setInt(26, sch.getStatus());
  500 + ps.setTimestamp(27, new java.sql.Timestamp(sch.getUpdateDate().getTime()));
  501 + ps.setString(28, sch.getXlBm());
  502 + ps.setString(29, sch.getXlDir());
  503 + ps.setString(30, sch.getXlName());
  504 + ps.setString(31, sch.getZdsj());
  505 + ps.setString(32, sch.getZdsjActual());
  506 + ps.setString(33, sch.getZdzCode());
  507 + ps.setString(34, sch.getZdzName());
  508 + ps.setInt(35, sch.getCcno()==null?0:sch.getCcno());
  509 + ps.setBoolean(36, sch.isDfAuto());
  510 + ps.setString(37, sch.getFgsBm());
  511 + ps.setString(38, sch.getFgsName());
  512 + ps.setString(39, sch.getGsBm());
  513 + ps.setString(40, sch.getGsName());
  514 + ps.setBoolean(41, sch.isOnline());
  515 + ps.setString(42, sch.getAdjustExps());
  516 + ps.setBoolean(43, sch.isReissue());
  517 + ps.setDouble(44, sch.getJhlcOrig());
  518 + ps.setInt(45, sch.getSiginCompate());
  519 + ps.setInt(46, sch.getDriftStatus());
  520 + ps.setBoolean(47, sch.isCcService());
  521 + ps.setString(48, sch.getMajorStationName());
  522 + }
  523 +
  524 + @Override
  525 + public int getBatchSize() {
  526 + return pstList.size();
  527 + }
  528 + });
  529 +
  530 + tran.commit(status);
  531 + }catch (Exception e){
  532 + tran.rollback(status);
  533 + logger.error("real schedule batchSave error...", e);
  534 + }
  535 + // 入库
  536 + //new BatchSaveUtils<ScheduleRealInfo>().saveList(list, ScheduleRealInfo.class);
  537 + }
  538 +
  539 + public List<SchedulePlanInfo> cleanSchPlanItr(Iterator<SchedulePlanInfo> itrab) {
  540 + List<SchedulePlanInfo> list = new ArrayList<>();
  541 +
  542 + SchedulePlanInfo sp;
  543 + while (itrab.hasNext()) {
  544 + sp = itrab.next();
  545 + sp.setSchedulePlan(null);
  546 + sp.setCreateBy(null);
  547 + sp.setUpdateBy(null);
  548 + list.add(sp);
  549 + }
  550 + return list;
  551 + }
  552 +
  553 + /**
  554 + * @Title: findByLineCode
  555 + * @Description: TODO(lineCode 获取班次)
  556 + */
  557 + public List<ScheduleRealInfo> findByLineCode(String lineCode) {
  558 + List<ScheduleRealInfo> rs = new ArrayList<>();
  559 +
  560 + Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();
  561 + for (ScheduleRealInfo sch : schs) {
  562 + if (sch.getXlBm().equals(lineCode))
  563 + rs.add(sch);
  564 + }
  565 + return rs;
  566 + }
  567 +
  568 + /**
  569 + * @Title: findByLineCode
  570 + * @Description: TODO(lineList 获取班次)
  571 + */
  572 + public Map<String, Collection<ScheduleRealInfo>> findByLineCodes(List<String> lineList) {
  573 + ArrayListMultimap<String, ScheduleRealInfo> mMap = ArrayListMultimap.create();
  574 +
  575 + Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();
  576 + for (ScheduleRealInfo sch : schs) {
  577 + if (lineList.contains(sch.getXlBm())) {
  578 + mMap.put(sch.getXlBm(), sch);
  579 + }
  580 + }
  581 + return mMap.asMap();
  582 + }
  583 +
  584 + /**
  585 + * @Title: findCarByLineCode
  586 + * @Description: TODO(线路下运营的车辆)
  587 + */
  588 + public Set<String> findCarByLineCode(String lineCode) {
  589 + /*Set<String> rs = new HashSet<>();
  590 +
  591 + Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();
  592 + for (ScheduleRealInfo sch : schs) {
  593 + if (sch.getXlBm().equals(lineCode))
  594 + rs.add(sch.getClZbh());
  595 + }
  596 +*/
  597 + return lineNbbmsMap.get(lineCode);
  598 + }
  599 +
  600 + public List<ScheduleRealInfo> findByNbbm(String nbbm) {
  601 + return nbbmScheduleMap.get(nbbm);
  602 + }
  603 +
  604 + /**
  605 + * @Title: findByLineAndUpDown
  606 + * @Description: TODO(lineCode 和走向获取班次)
  607 + */
  608 + public List<ScheduleRealInfo> findByLineAndUpDown(String lineCode, Integer upDown) {
  609 + List<ScheduleRealInfo> list = findByLineCode(lineCode), rs = new ArrayList<>();
  610 +
  611 + for (ScheduleRealInfo sch : list) {
  612 + if (sch.getXlDir().equals(upDown + ""))
  613 + rs.add(sch);
  614 + }
  615 + return rs;
  616 + }
  617 +
  618 + public ScheduleRealInfo get(long id) {
  619 + return id2SchedulMap.get(id);
  620 + }
  621 +
  622 +
  623 + /**
  624 + * @Title: next
  625 + * @Description: TODO(下一个班次)
  626 + */
  627 + public ScheduleRealInfo next(ScheduleRealInfo sch) {
  628 + List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());
  629 + //排序
  630 + Collections.sort(list, schDFSJComparator);
  631 + return next(list, sch);
  632 + }
  633 +
  634 +
  635 + /**
  636 + * 下一个班次
  637 + *
  638 + * @param list 班次集合
  639 + * @param sch 当前班次
  640 + * @return
  641 + */
  642 + private ScheduleRealInfo next(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {
  643 + int outConfig = -1;
  644 + LineConfig config = lineConfigData.get(sch.getXlBm());
  645 + if (config != null)
  646 + outConfig = config.getOutConfig();
  647 +
  648 + //限定出站既出场的停车场
  649 + List<String> parks = config.findTwinsParkList();
  650 + boolean limitPark = null != parks && parks.size() > 0;
  651 + boolean flag = false;
  652 + ScheduleRealInfo next = null;
  653 + for (ScheduleRealInfo temp : list) {
  654 + if (temp.getId() == sch.getId()) {
  655 + flag = true;
  656 + continue;
  657 + }
  658 + //忽略烂班
  659 + if (temp.isDestroy())
  660 + continue;
  661 +
  662 + //出站既出场,忽略出场班次
  663 + if (outConfig == 2 && temp.getBcType().equals("out") && isEmptyMileage(temp)
  664 + && (!limitPark || parks.contains(temp.getQdzCode())))
  665 + continue;
  666 +
  667 + if (flag) {
  668 + next = temp;
  669 + break;
  670 + }
  671 + }
  672 + return next;
  673 + }
  674 +
  675 + private boolean isEmptyMileage(ScheduleRealInfo sch) {
  676 + return sch.getBcsj() == 0 || sch.getJhlcOrig().intValue() == 0;
  677 + }
  678 +
  679 + /**
  680 + * 下一个班次
  681 + *
  682 + * @param list 班次集合
  683 + * @param sch 当前班次
  684 + * @return
  685 + */
  686 + private ScheduleRealInfo next2_lp(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {
  687 + int outConfig = -1;
  688 + LineConfig config = lineConfigData.get(sch.getXlBm());
  689 + if (config != null)
  690 + outConfig = config.getOutConfig();
  691 +
  692 + boolean flag = false;
  693 + ScheduleRealInfo next = null;
  694 + for (ScheduleRealInfo temp : list) {
  695 + if (temp.getId() == sch.getId()) {
  696 + flag = true;
  697 + continue;
  698 + }
  699 +
  700 + if (flag) {
  701 + next = temp;
  702 + break;
  703 + }
  704 + }
  705 + return next;
  706 + }
  707 +
  708 + private ScheduleRealInfo next3_lp(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {
  709 + int outConfig = -1;
  710 + LineConfig config = lineConfigData.get(sch.getXlBm());
  711 + if (config != null)
  712 + outConfig = config.getOutConfig();
  713 +
  714 + //限定出站既出场的停车场
  715 + List<String> parks = config.findTwinsParkList();
  716 + boolean limitPark = null != parks && parks.size() > 0;
  717 + boolean flag = false;
  718 + ScheduleRealInfo next = null;
  719 + for (ScheduleRealInfo temp : list) {
  720 + if (temp.getId() == sch.getId()) {
  721 + flag = true;
  722 + continue;
  723 + }
  724 +
  725 + //出站既出场,忽略出场班次
  726 + if (outConfig == 2 && temp.getBcType().equals("out") && isEmptyMileage(temp)
  727 + && (!limitPark || parks.contains(temp.getQdzCode())))
  728 + continue;
  729 +
  730 + if (flag) {
  731 + next = temp;
  732 + break;
  733 + }
  734 + }
  735 + return next;
  736 + }
  737 +
  738 + /**
  739 + * 上一个班次
  740 + *
  741 + * @param sch
  742 + * @return
  743 + */
  744 + public ScheduleRealInfo prev(ScheduleRealInfo sch) {
  745 + List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());
  746 +
  747 + //boolean flag = false;
  748 + ScheduleRealInfo prev = null;
  749 + int size = list.size();
  750 +
  751 + for (int i = 0; i < size; i++) {
  752 + if (list.get(i).isDestroy())
  753 + continue;
  754 +
  755 + if (list.get(i).getId().equals(sch.getId())) {
  756 + return prev;
  757 + }
  758 + prev = list.get(i);
  759 + }
  760 + return prev;
  761 + }
  762 +
  763 + /**
  764 + * 是否是首班出场
  765 + *
  766 + * @param sch
  767 + * @return
  768 + */
  769 + public boolean isFirstOut(ScheduleRealInfo sch) {
  770 + List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());
  771 + try {
  772 + if (list.get(0) == sch && sch.getBcType().equals("out"))
  773 + return true;
  774 + } catch (IndexOutOfBoundsException e) {
  775 + logger.error("小小的数组越界,无伤大雅!");
  776 + }
  777 + return false;
  778 + }
  779 +
  780 + public void put(ScheduleRealInfo sch) {
  781 + schAttrCalculator
  782 + .calcRealDate(sch)
  783 + .calcAllTimeByFcsj(sch);
  784 +
  785 + nbbmScheduleMap.put(sch.getClZbh(), sch);
  786 +
  787 + //主键索引
  788 + id2SchedulMap.put(sch.getId(), sch);
  789 + //路牌对照表
  790 + addLPMapp(sch);
  791 +
  792 + //跨24点的,再save一次
  793 + if (!sch.getRealExecDate().equals(sch.getScheduleDateStr()))
  794 + save(sch);
  795 + }
  796 +
  797 + public void addLPMapp(ScheduleRealInfo sch) {
  798 + lpScheduleMap.put(sch.getXlBm() + "_" + sch.getLpName(), sch);
  799 + }
  800 +
  801 + public void delete(ScheduleRealInfo sch) {
  802 + if (!sch.isSflj())
  803 + return;
  804 +
  805 + nbbmScheduleMap.remove(sch.getClZbh(), sch);
  806 + id2SchedulMap.remove(sch.getId());
  807 + lpScheduleMap.remove(sch.getXlBm() + "_" + sch.getLpName(), sch);
  808 +
  809 + //如果正在执行该班次
  810 + if (carExecutePlanMap.get(sch.getClZbh()) == sch) {
  811 + //重新计算车辆当前执行班次
  812 + reCalcExecPlan(sch.getClZbh());
  813 + }
  814 + }
  815 +
  816 + public List<ScheduleRealInfo> updateQdzTimePlan(String lpName) {
  817 + List<ScheduleRealInfo> list = lpScheduleMap.get(lpName);
  818 + Collections.sort(list, schFCSJComparator);
  819 + return schAttrCalculator.updateQdzTimePlan(list);
  820 + }
  821 +
  822 + public List<ScheduleRealInfo> updateQdzTimePlan(ScheduleRealInfo sch) {
  823 + return updateQdzTimePlan(sch.getXlBm() + "_" + sch.getLpName());
  824 + }
  825 +
  826 + /**
  827 + * @Title: doneSum
  828 + * @Description: TODO(已完成班次总数)
  829 + */
  830 + public int doneSum(String clZbh) {
  831 + List<ScheduleRealInfo> list = nbbmScheduleMap.get(clZbh);
  832 + int rs = 0;
  833 +
  834 + for (ScheduleRealInfo sch : list) {
  835 + if (sch.getStatus() == 2 && !sch.isDestroy())
  836 + rs++;
  837 + }
  838 + return rs;
  839 + }
  840 +
  841 + public void save(ScheduleRealInfo sch) {
  842 + sch.setUpdateDate(new Date());
  843 + pstBuffer.add(sch);
  844 + }
  845 +
  846 +
  847 + /**
  848 + * @Title: nextByBcType
  849 + * @Description: TODO(获取下一个指定班次类型的班次)
  850 + */
  851 + public ScheduleRealInfo nextByBcType(String nbbm, String bcType) {
  852 + List<ScheduleRealInfo> list = findByBcType(nbbm, bcType);
  853 +
  854 + Collections.sort(list, schFCSJComparator);
  855 + ScheduleRealInfo sch = null;
  856 + for (ScheduleRealInfo temp : list) {
  857 + if (temp.getFcsjActual() == null)
  858 + sch = temp;
  859 + }
  860 +
  861 + return sch;
  862 + }
  863 +
  864 +
  865 + /**
  866 + * 搜索离当前时间最近的一个指定类型的班次
  867 + *
  868 + * @param nbbm
  869 + * @param bcType
  870 + * @return
  871 + */
  872 + public ScheduleRealInfo searchNearByBcType(String nbbm, String bcType) {
  873 + List<ScheduleRealInfo> list = findByBcType(nbbm, bcType);
  874 + Collections.sort(list, schFCSJComparator);
  875 +
  876 + long t = System.currentTimeMillis();
  877 + int distance = -1, diff;
  878 +
  879 + ScheduleRealInfo sch = null;
  880 + for (ScheduleRealInfo temp : list) {
  881 + diff = (int) Math.abs(temp.getDfsjT() - t);
  882 + if (diff < distance || distance == -1) {
  883 + sch = temp;
  884 + distance = diff;
  885 + }
  886 + }
  887 + return sch;
  888 + }
  889 +
  890 + public List<ScheduleRealInfo> findByBcType(String nbbm, String bcType) {
  891 + List<ScheduleRealInfo> all = nbbmScheduleMap.get(nbbm), outList = new ArrayList<>();
  892 +
  893 + for (ScheduleRealInfo sch : all) {
  894 + if (sch.getBcType().equals(bcType))
  895 + outList.add(sch);
  896 + }
  897 + return outList;
  898 + }
  899 +
  900 + public Collection<ScheduleRealInfo> findAll() {
  901 + return nbbmScheduleMap.values();
  902 + }
  903 +
  904 + public Collection<ScheduleRealInfo> findAllByLpContainer() {
  905 + return lpScheduleMap.values();
  906 + }
  907 +
  908 + public Collection<ScheduleRealInfo> findAllByIdContainer() {
  909 + return id2SchedulMap.values();
  910 + }
  911 +
  912 + public int getPstSize() {
  913 + return pstBuffer.size();
  914 + }
  915 +
  916 + public boolean addExecPlan(ScheduleRealInfo sch) {
  917 + ScheduleRealInfo oldExec = executeCurr(sch.getClZbh());
  918 + if (sch != null){
  919 + if(sch.getStatus()==2)
  920 + reCalcExecPlan(sch.getClZbh());
  921 + else
  922 + carExecutePlanMap.put(sch.getClZbh(), sch);
  923 + }
  924 + else
  925 + carExecutePlanMap.remove(sch.getClZbh());
  926 +
  927 + return executeCurr(sch.getClZbh()) != oldExec;
  928 + }
  929 +
  930 + public void removeExecPlan(String clzbh) {
  931 + carExecutePlanMap.remove(clzbh);
  932 + }
  933 +
  934 + public Map<String, ScheduleRealInfo> execPlanMap() {
  935 + return carExecutePlanMap;
  936 + }
  937 +
  938 + /**
  939 + * 车辆当前执行的班次
  940 + *
  941 + * @param nbbm
  942 + * @return
  943 + */
  944 + public ScheduleRealInfo executeCurr(String nbbm) {
  945 + if(StringUtils.isEmpty(nbbm))
  946 + return null;
  947 + return carExecutePlanMap.get(nbbm);
  948 + }
  949 +
  950 + /**
  951 + * @param @param sch
  952 + * @param @param newClZbh 新的车辆自编号
  953 + * @Title: changeCar
  954 + * @Description: TODO(班次换车) 返回有更新的班次
  955 + */
  956 + public List<ScheduleRealInfo> changeCar(ScheduleRealInfo sch, String newClZbh) {
  957 + List<ScheduleRealInfo> ups = new ArrayList<>();
  958 +
  959 + String oldClZbh = sch.getClZbh();
  960 + //变更相关映射信息
  961 + nbbmScheduleMap.remove(sch.getClZbh(), sch);
  962 +
  963 + sch.setClZbh(newClZbh);
  964 + if (!nbbmScheduleMap.containsEntry(newClZbh, sch)) {
  965 + nbbmScheduleMap.put(newClZbh, sch);
  966 + }
  967 +
  968 + //重新计算车辆当前执行班次
  969 + reCalcExecPlan(newClZbh);
  970 + reCalcExecPlan(oldClZbh);
  971 + //重新分组计划用车
  972 + reCalcLineNbbms();
  973 + return ups;
  974 + }
  975 +
  976 + public void removeNbbm2SchMapp(ScheduleRealInfo sch) {
  977 + nbbmScheduleMap.remove(sch.getClZbh(), sch);
  978 + }
  979 +
  980 + public void addNbbm2SchMapp(ScheduleRealInfo sch) {
  981 + nbbmScheduleMap.put(sch.getClZbh(), sch);
  982 + }
  983 +
  984 + public void reCalcExecPlan(String nbbm) {
  985 + List<ScheduleRealInfo> list = nbbmScheduleMap.get(nbbm);
  986 + Collections.sort(list, schDFSJComparator);
  987 +
  988 + ScheduleRealInfo sch = schAttrCalculator.calcCurrentExecSch(list);
  989 + if(null != sch)
  990 + carExecutePlanMap.put(nbbm, sch);
  991 + else
  992 + carExecutePlanMap.remove(nbbm);
  993 + }
  994 +
  995 + /**
  996 + * 空驶任务?
  997 + * 出场、进场、直放、两点间空驶
  998 + * @param sch
  999 + * @return
  1000 + */
  1001 + public static boolean emptyService(ScheduleRealInfo sch){
  1002 + String type = sch.getBcType();
  1003 + return type.equals("out") || type.equals("in") || type.equals("venting") || type.equals("ldks");
  1004 + }
  1005 +
  1006 + @Autowired
  1007 + JdbcTemplate jdbcTemplate;
  1008 +
  1009 + /**
  1010 + * 删除实际排班
  1011 + *
  1012 + * @param lineCode
  1013 + * @return
  1014 + */
  1015 + public Map<String, Object> deleteRealSchedule(String lineCode) {
  1016 + Map<String, Object> rs = new HashMap<>();
  1017 +
  1018 + try {
  1019 + String rq = currSchDateMap.get(lineCode);
  1020 + if (StringUtils.isNotEmpty(rq)) {
  1021 + List<ScheduleRealInfo> all = findByLineCode(lineCode);
  1022 +
  1023 + if(null != all && all.size() > 0){
  1024 + //解除gps 和班次之间的关联
  1025 + List<ScheduleRealInfo> unions = calcUnion(all, carExecutePlanMap.values());
  1026 + for (ScheduleRealInfo sch : unions) {
  1027 + removeExecPlan(sch.getClZbh());
  1028 + }
  1029 + //解除调度指令和班次的外键约束
  1030 + StringBuilder inStr = new StringBuilder("(");
  1031 + for (ScheduleRealInfo sch : all) {
  1032 + inStr.append(sch.getId() + ",");
  1033 + }
  1034 + inStr.deleteCharAt(inStr.length() - 1).append(")");
  1035 + jdbcTemplate.update(Constants.MULTI_REMOVE_DIRECTIVE_SCH_FK + " " + inStr.toString());
  1036 + jdbcTemplate.update("update bsth_c_s_child_task set schedule = null where schedule in " + inStr.toString());
  1037 + }
  1038 +
  1039 + //删除班次数据
  1040 + removeRealSch(lineCode, rq);
  1041 +
  1042 + }
  1043 + rs.put("status", ResponseCode.SUCCESS);
  1044 + } catch (Exception e) {
  1045 + logger.error("", e);
  1046 + rs.put("status", ResponseCode.ERROR);
  1047 + if (e instanceof DataIntegrityViolationException)
  1048 + rs.put("msg", "失败,违反数据约束!!");
  1049 + else
  1050 + rs.put("msg", e.getMessage());
  1051 + }
  1052 +
  1053 + return rs;
  1054 + }
  1055 +
  1056 + /**
  1057 + * 计算并集
  1058 + *
  1059 + * @param all
  1060 + * @param sub
  1061 + * @return
  1062 + */
  1063 + public List<ScheduleRealInfo> calcUnion(Collection<ScheduleRealInfo> c1, Collection<ScheduleRealInfo> c2) {
  1064 + List<ScheduleRealInfo> rs = new ArrayList<>();
  1065 +
  1066 + for (ScheduleRealInfo sch : c1) {
  1067 + if (c2.contains(sch)) {
  1068 + rs.add(sch);
  1069 + }
  1070 + }
  1071 + return rs;
  1072 + }
  1073 +
  1074 + /**
  1075 + * 覆盖一辆车的所有班次
  1076 + *
  1077 + * @param nbbm
  1078 + * @param sets
  1079 + */
  1080 + public void replaceByNbbm(String nbbm, Collection<ScheduleRealInfo> sets) {
  1081 + nbbmScheduleMap.removeAll(nbbm);
  1082 + nbbmScheduleMap.putAll(nbbm, sets);
  1083 + }
  1084 +
  1085 + /**
  1086 + * 获取该班次所在路牌的下一个班次
  1087 + *
  1088 + * @param sch
  1089 + * @return
  1090 + */
  1091 + public ScheduleRealInfo nextByLp(ScheduleRealInfo sch) {
  1092 + List<ScheduleRealInfo> list = lpScheduleMap.get(sch.getXlBm() + "_" + sch.getLpName());
  1093 + Collections.sort(list, schFCSJComparator);
  1094 + return next3_lp(list, sch);
  1095 + }
  1096 +
  1097 + /**
  1098 + * 获取该班次所在路牌的下一个班次,不考虑场既是站
  1099 + *
  1100 + * @param sch
  1101 + * @return
  1102 + */
  1103 + public ScheduleRealInfo nextByLp2(ScheduleRealInfo sch) {
  1104 + List<ScheduleRealInfo> list = lpScheduleMap.get(sch.getXlBm() + "_" + sch.getLpName());
  1105 + Collections.sort(list, schFCSJComparator);
  1106 + return next2_lp(list, sch);
  1107 + }
  1108 +
  1109 + public ArrayListMultimap<String, ScheduleRealInfo> getLpScheduleMap() {
  1110 + return lpScheduleMap;
  1111 + }
  1112 +
  1113 + /**
  1114 + * 重新全量计算路牌下的班次关联性
  1115 + * 临时性的函数
  1116 + */
  1117 + public void _test_reCalcLpSch() {
  1118 + Map<String ,Collection<ScheduleRealInfo>> map = lpScheduleMap.asMap();
  1119 + Set<String> ks = map.keySet();
  1120 + for(String k : ks){
  1121 + schAttrCalculator.calcQdzTimePlan(new ArrayList<ScheduleRealInfo>(map.get(k)));
  1122 + }
  1123 + }
  1124 +
  1125 + public int dbCount(String lineCode, String currSchDate) {
  1126 + int count = -1;
  1127 +
  1128 + try{
  1129 + count = jdbcTemplate.queryForObject("select count(*) from bsth_c_s_sp_info_real where schedule_date='"+currSchDate+"' and xl_bm='"+lineCode+"'", java.lang.Integer.class);
  1130 +
  1131 + }catch (Exception e){
  1132 + logger.error("", e);
  1133 + }
  1134 + return count;
  1135 + }
  1136 +
  1137 + /**
  1138 + * 重新计算ID对照map
  1139 + */
  1140 + public int reCalcIdMaps(){
  1141 + Collection<ScheduleRealInfo> all = findAll();
  1142 + ConcurrentMap<Long, ScheduleRealInfo> id2SchedulMapCopy = new ConcurrentHashMap<>();
  1143 +
  1144 + for(ScheduleRealInfo sch : all){
  1145 + id2SchedulMapCopy.put(sch.getId(), sch);
  1146 + }
  1147 +
  1148 + id2SchedulMap = id2SchedulMapCopy;
  1149 +
  1150 + return id2SchedulMap.size();
  1151 + }
  1152 +
  1153 + /**
  1154 + * 重新计算线路计划用车
  1155 + */
  1156 + public void reCalcLineNbbms(){
  1157 + HashMultimap<String, String> multimap = HashMultimap.create();
  1158 +
  1159 + Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();
  1160 + for (ScheduleRealInfo sch : schs) {
  1161 + multimap.put(sch.getXlBm(), sch.getClZbh());
  1162 + }
  1163 +
  1164 + lineNbbmsMap = multimap;
  1165 + }
  1166 +
  1167 + public String sizeString(){
  1168 + return id2SchedulMap.size() + "/" + nbbmScheduleMap.size();
  1169 + }
  1170 +
  1171 +
  1172 + /**
  1173 + * 按公司编码分组数据
  1174 + */
  1175 + public void groupByGsbm(){
  1176 + Collection<ScheduleRealInfo> all = findAll();
  1177 + ListMultimap<String, ScheduleRealInfo> gsBmMaps = ArrayListMultimap.create();
  1178 +
  1179 + for(ScheduleRealInfo sch : all){
  1180 + gsBmMaps.put(sch.getGsBm(), sch);
  1181 + }
  1182 +
  1183 + if(gsBmMaps.size() > 0){
  1184 + gsBmScheduleMap = null;
  1185 + gsBmScheduleMap = gsBmMaps;
  1186 + }
  1187 + }
  1188 +
  1189 + public Collection<ScheduleRealInfo> findByGsbm(String gsbm){
  1190 + return gsBmScheduleMap.get(gsbm);
  1191 + }
1164 } 1192 }
1165 \ No newline at end of file 1193 \ No newline at end of file