Commit 721657ed445192f0ce4f881251e44629d3962af9

Authored by 王通
1 parent 875e4f3b

1.

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