SchAttrCalculator.java 8.25 KB
package com.bsth.data.schedule;

import com.bsth.data.LineConfigData;
import com.bsth.entity.realcontrol.LineConfig;
import com.bsth.entity.realcontrol.ScheduleRealInfo;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 
 * @ClassName: SchAttrCalculator
 * @Description: TODO(班次相关属性计算器)
 * @author PanZhao
 * @date 2016年8月15日 下午4:40:26
 *
 */
@Component
public class SchAttrCalculator {

	@Autowired
	LineConfigData lineConfigData;

	private final static long DAY_TIME = 1000 * 60 * 60 * 24L;

	Logger logger = LoggerFactory.getLogger(this.getClass());

	private static DateTimeFormatter fmtyyyyMMdd = DateTimeFormat.forPattern("yyyy-MM-dd")
			,fmtHHmm = DateTimeFormat.forPattern("HH:mm")
			,fmtyyyyMMddHHmm = DateTimeFormat.forPattern("yyyy-MM-ddHH:mm");

	/**
	 * @Title: calcRealDate
	 * @Description: TODO(计算班次的真实执行日期)
	 */
	public SchAttrCalculator calcRealDate(ScheduleRealInfo sch) {
		LineConfig conf = lineConfigData.get(sch.getXlBm());

		try {
			if (null == sch.getFcsjT())
				calcFcsjTime(sch);

			//计发時間
			if(sch.getFcsj().compareTo(conf.getStartOpt()) < 0){
				sch.setFcsjAll(fmtyyyyMMddHHmm.parseMillis(sch.getScheduleDateStr()+sch.getFcsj()) + DAY_TIME);
			}

			//待发時間
			if(sch.getDfsj().compareTo(conf.getStartOpt()) < 0){
				sch.setDfsjAll(fmtyyyyMMddHHmm.parseMillis(sch.getScheduleDateStr()+sch.getDfsj()) + DAY_TIME);
			}
			else
				sch.setDfsjAll(fmtyyyyMMddHHmm.parseMillis(sch.getScheduleDateStr()+sch.getDfsj()));

			//实发時間
			if(StringUtils.isNotEmpty(sch.getFcsjActual()) &&
					sch.getFcsjActual().compareTo(conf.getStartOpt()) < 0){
				sch.setFcsjActualAll(fmtyyyyMMddHHmm.parseMillis(sch.getScheduleDateStr()+sch.getFcsjActual()) + DAY_TIME);
			}

			//实际终点時間
			if(StringUtils.isNotEmpty(sch.getZdsjActual()) &&
					sch.getZdsjActual().compareTo(conf.getStartOpt()) < 0){
				sch.setZdsjActualAll(fmtyyyyMMddHHmm.parseMillis(sch.getScheduleDateStr()+sch.getZdsjActual()) + DAY_TIME);
			}

			sch.setRealExecDate(fmtyyyyMMdd.print(sch.getFcsjT()));
		} catch (Exception e) {
			logger.error("", e);
		}
		return this;
	}

	/**
	 * 
	 * @Title: calcAllTimeByFcsj
	 * @Description: TODO(根据发车时间字符串计算 (计发时间,终点时间,待发时间))
	 */
	public SchAttrCalculator calcAllTimeByFcsj(ScheduleRealInfo sch) {
		try {
			// 生成时间戳
			calcTimestamp(sch);
			
			// 计划终点时间
			if (sch.getBcsj() != null) {
				sch.setZdsjT(sch.getDfsjT() + (sch.getBcsj() * 60 * 1000));
				sch.setZdsj(fmtHHmm.print(sch.getZdsjT()));
			}
		} catch (ParseException e) {
			logger.error("", e);
		}
		return this;
	}
	
	/**
	 * 
	 * @Title: calcQdzTimePlan 
	 * @Description: TODO(计算班次的起点应到时间)
	 */
	public void calcQdzTimePlan(List<ScheduleRealInfo> list){
		Collections.sort(list, new ScheduleComparator.FCSJ());
		
		int len = list.size();
		if(len == 0)
			return;
		
		ScheduleRealInfo prve = list.get(0), curr;
		for(int i = 1; i < len; i ++){
			curr = list.get(i);

			if(isJoin(prve, curr)){
				curr.setQdzArrDatejh(prve.getZdsj());
				if(StringUtils.isNotEmpty(prve.getZdsjActual()))
					curr.setQdzArrDatesj(prve.getZdsjActual());
			}
			prve = curr;
		}
	}

	private boolean isJoin(ScheduleRealInfo prve, ScheduleRealInfo curr) {
		return prve.getZdzName().equals(curr.getQdzName())//名称相等
				|| prve.getZdzCode().equals(curr.getQdzCode())//编码相等
				|| prve.getZdzName().startsWith(curr.getQdzName())//起始包括
				|| curr.getQdzName().startsWith(prve.getZdzName());//起始包括
	}
	
	/**
	 * 
	 * @Title: updateQdzTimePlan 
	 * @Description: TODO(更新班次的起点应到时间) 并返回被更新的班次
	 */
	public List<ScheduleRealInfo> updateQdzTimePlan(List<ScheduleRealInfo> list){
		Collections.sort(list, new ScheduleComparator.FCSJ());
		
		List<ScheduleRealInfo> updateList = new ArrayList<>();
		int len = list.size();
		if(len == 0)
			return updateList;
		
		ScheduleRealInfo prve = list.get(0), curr;
		for(int i = 1; i < len; i ++){
			curr = list.get(i);
			
			if(prve.getZdzName().equals(curr.getQdzName())
					|| prve.getZdzCode().equals(curr.getQdzCode())){
				
				if(curr.getQdzArrDatejh() != null && prve.getZdsj().equals(curr.getQdzArrDatejh())){
					prve = curr;
					continue;
				}
					
				curr.setQdzArrDatejh(prve.getZdsj());
				updateList.add(curr);
			}
			else{
				curr.setQdzArrDatejh(null);
				updateList.add(curr);
			}
			prve = curr;
		}
		
		return updateList;
	}

	public SchAttrCalculator calcFcsjTime(ScheduleRealInfo sch) throws ParseException {
		sch.setFcsjT(fmtyyyyMMddHHmm.parseMillis(sch.getRealExecDate() + sch.getFcsj()));
		return this;
	}
	
	public void calcTimestamp(ScheduleRealInfo sch) throws ParseException{
		//计发时间
		if(sch.getFcsjT() == null)
			calcFcsjTime(sch);
		
		//待发时间
		if(sch.getDfsj() == null)
			sch.setDfsjAll(sch.getFcsjT());
		if(sch.getDfsjT() == null)
			sch.setDfsjAll(sch.getDfsj());
		
		//实发时间戳
		if(sch.getFcsjActualTime() == null && sch.getFcsjActual() != null)
			sch.setFcsjActualAll(sch.getFcsjActual());
		
		//实达时间戳
		if(sch.getZdsjActualTime() == null && sch.getZdsjActual() != null)
			sch.setZdsjActualAll(sch.getZdsjActual());
	}

	/**
	 * 计算当前要执行的班次
	 * @param list
	 * @return
	 */
	public ScheduleRealInfo calcCurrentExecSch(List<ScheduleRealInfo> list){
		String lineCode = list.get(0).getXlBm();
		LineConfig conf = lineConfigData.get(lineCode);
		long t = System.currentTimeMillis();
		int outConfig = -1;
		//限定出站既出场的停车场
		String park = null;
		if(conf != null){
			outConfig = conf.getOutConfig();
			park = conf.getTwinsPark();
		}
		boolean limitPark = StringUtils.isNotEmpty(park);

		for(ScheduleRealInfo sch : list){
			//如果是出站既出场,忽略出场班次
			if(outConfig == 2 && sch.getBcType().equals("out")
					&& (!limitPark || park.equals(sch.getQdzCode())))
				continue;

			//忽略烂班
			if(sch.isDestroy())
				continue;

			//已执行
			if(StringUtils.isNotEmpty(sch.getZdsjActual()))
				continue;

			if(Math.abs((t - sch.getDfsjT())) > 1000 * 60 * 60){
				//差值较大,倒着找看有没有更合适的
				ScheduleRealInfo schReverse = calcCurrentExecSchReverse(list, outConfig, limitPark, park);
				if(null != schReverse && !schReverse.getId().equals(sch.getId())){
					logger.info("calc_current_exec_sch_reverse... -" + schReverse.getId());
					return suitableExecSch(schReverse, sch, t);
				}
			}
			return sch;
		}
		return null;
	}

	/**
	 * 反转匹配一个班次
	 * @param list
	 * @param outConfig
	 * @param limitPark
	 * @param park
	 * @return
	 */
	private ScheduleRealInfo calcCurrentExecSchReverse(List<ScheduleRealInfo> list, int outConfig, boolean limitPark, String park){
		ScheduleRealInfo near = null;
		for(ScheduleRealInfo sch : list){
			//如果是出站既出场,忽略出场班次
			if(outConfig == 2 && isInout(sch)
					&& (!limitPark || park.equals(sch.getQdzCode()) || park.equals(sch.getZdzCode())))
				continue;

			//忽略烂班
			if(sch.isDestroy())
				continue;

			if(StringUtils.isNotEmpty(sch.getZdsjActual())){
				near = null;
				continue;
			}

			if(null == near)
				near = sch;
		}
		return near;
	}

	/**
	 * 比较2个班次,谁是指定时间更合适执行的
	 * @param schReverse
	 * @param sch
	 * @param t
	 * @return
	 */
	private ScheduleRealInfo suitableExecSch(ScheduleRealInfo schReverse, ScheduleRealInfo sch, long t){
		return Math.abs(t - schReverse.getDfsjT()) > Math.abs(t - sch.getDfsjT())?sch: schReverse;
	}

	private boolean isInout(ScheduleRealInfo sch){
		return sch.getBcType().equals("out") || sch.getBcType().equals("in");
	}
}