package nc.bs.mmpac.pmo.pac0002.bp;

import java.util.ArrayList;
import java.util.List;

import nc.bs.mmpac.pmo.pac0002.bp.rule.AfterApprovingSynchronizeRuleRZ;
import nc.bs.mmpac.pmo.pac0002.pluginpoint.PMOPluginPoint;
import nc.bs.mmpac.pmo.pac0002.rule.PMOATPUpdateRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOAdjustReserveRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOBatchCodeEditRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOBatchCodeEditSynPickmRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOCffileidInserAndUpdatetRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOCreateVersionRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOMarkWrSNWhenUpdateRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOProcedureSortRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOSyncSNWhenItemDeleteRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOSyncSNWhenUpdateRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOUpdatePickmRule;
import nc.bs.mmpac.pmo.pac0002.rule.PMOUpdateSaveApproveRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckApproveOperTypeRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckDateLogicRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckDispatchNumRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckOutputNumRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckPlanDateTimeRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckPlanPutNumRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckPlanPutNumberRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckProcedureDateLogicRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckProcedureDupRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckProcedureNotNullRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckProdurepointRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckPutNumRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckSNNumAndUnitRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckSaveNotNullRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOCheckSnBindRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOProcedureChkPntRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMOProcedurePutCheckRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMORwkProcCheckRule;
import nc.bs.mmpac.pmo.pac0002.rule.check.PMORwkProcOperTypeRule;
import nc.bs.mmpac.pmo.pac0002.rule.fill.PMOFillBatchCodeRule;
import nc.bs.mmpac.pmo.pac0002.rule.fill.PMOFillInsertPlanTimeByProcedureRule;
import nc.bs.mmpac.pmo.pac0002.rule.fill.PMOFillSNPkAndCodeRule;
import nc.bs.mmpac.pmo.pac0002.rule.grand.PMOIsCreatPlanOutputRule;
import nc.bs.mmpac.pmo.pac0002.rule.grand.PMORecalProcedureRule;
import nc.bs.mmpac.pmo.pac0002.rule.rewrite.RewriteUpdateNum4INVP;
import nc.bs.mmpac.pmo.pac0002.rule.rewrite.RewriteUpdateNum4MPS;
import nc.bs.mmpac.pmo.pac0002.rule.rewrite.RewriteUpdateNum4PMO;
import nc.bs.mmpac.pmo.pac0002.rule.rewrite.RewriteUpdateNum4PSCRecive;
import nc.bs.mmpac.pmo.pac0002.rule.rewrite.RewriteUpdateNum4PSM;
import nc.bs.mmpac.pmo.pac0002.rule.rewrite.RewriteUpdateNum4Renovate;
import nc.bs.mmpac.pmo.pac0002.rule.rewrite.RewriteUpdateNum4SFC;
import nc.bs.mmpac.pmo.pac0002.rule.rewrite.RewriteUpdateNum4SO;
import nc.bs.mmpac.pmo.pac0002.rule.rewrite.RewriteUpdateNum4TO;
import nc.bs.mmpub.rule.MMVOSagaFrozenValidateRule;
import nc.bs.pubapp.pub.rule.BillCodeCheckRule;
import nc.impl.pubapp.pattern.rule.ICompareRule;
import nc.impl.pubapp.pattern.rule.IRule;
import nc.impl.pubapp.pattern.rule.processer.CompareAroundProcesser;
import nc.util.mmf.framework.base.MMArrayUtil;
import nc.util.mmf.framework.gc.GCUpdateBPTemplate;
import nc.vo.mmpac.pmo.pac0002.constant.PMOConst;
import nc.vo.mmpac.pmo.pac0002.entity.PMOAggVO;
import nc.vo.mmpac.pmo.pac0002.entity.PMOHeadVO;
import nc.vo.mmpac.pmo.pac0002.util.PmoSagaUtil;
import nc.vo.pub.VOStatus;

/**
 * 订单变更业务处理<br>
 * 
 * @since 6.31
 * @version 2013-6-18 上午11:33:58
 * @author wanghjd
 */
public class PMOAdjustBP {

	public PMOAggVO[] adjust(PMOAggVO[] fullBills, PMOAggVO[] originBills) {
		if (MMArrayUtil.isEmpty(fullBills)) {
			return null;
		}

		for (PMOAggVO vo : fullBills) {
			if (vo.getParent().getStatus() != VOStatus.UPDATED) {
				vo.getParent().setStatus(VOStatus.UPDATED);
			}
		}
		// sagas冻结并开启saga
		PmoSagaUtil.frozenAndAddSaga(fullBills);
		// 调用修改模板
		GCUpdateBPTemplate<PMOAggVO> bp = new GCUpdateBPTemplate<PMOAggVO>(PMOPluginPoint.ADJUST);
		// 执行前规则
		this.addBeforeRule(bp.getAroundProcesser());
		// 执行后规则
		this.addAfterRule(bp.getAroundProcesser());
		PMOAggVO[] rets = bp.update(fullBills, originBills);
		// 修改保存补偿
		PmoSagaUtil.compensate4Update(rets.clone(), originBills);
		return rets;
	}

	private void addBeforeRule(CompareAroundProcesser<PMOAggVO> processer) {
		// 校验冻结状态 added by fengjinga
		IRule<PMOAggVO> checkFrozenRule = new MMVOSagaFrozenValidateRule<PMOAggVO>(false);
		processer.addBeforeRule(checkFrozenRule);
		// 校验单据号唯一性
		IRule<PMOAggVO> checkUniqueRule = new BillCodeCheckRule(PMOConst.PMO_BILLTYPE, PMOHeadVO.VBILLCODE,
				PMOHeadVO.PK_GROUP, PMOHeadVO.PK_ORG);
		// 把工序按工序号排序
		processer.addBeforeRule(new PMOProcedureSortRule());
		// 表头的交易类型，表体的物料、数量、计划投入数量不能为空
		IRule<PMOAggVO> checNullRule = new PMOCheckSaveNotNullRule(false);
		processer.addBeforeRule(checNullRule);
		// (变更专用)计划开工时间和计划完工时间可空，但是不能同时为空
		IRule<PMOAggVO> daterule = new PMOCheckPlanDateTimeRule();
		processer.addBeforeRule(daterule);
		// （变更专用）工序计划联动规则；
		ICompareRule<PMOAggVO> recalproc = new PMORecalProcedureRule();
		processer.addBeforeRule(recalproc);
		// (变更专用)验证修改计划投入数量后，需满足大于等于已完工数量
		IRule<PMOAggVO> checkPutNumRule = new PMOCheckPutNumRule();
		processer.addBeforeRule(checkPutNumRule);
		// (变更专用)计划产出数量不可小于订单的被预留数量
		IRule<PMOAggVO> checkOutputNumRule = new PMOCheckOutputNumRule();
		processer.addBeforeRule(checkOutputNumRule);
		// (变更专用)校验订单的计划投入数量不能小于该订单对应的所有投放计划的计划投放数量之和
		IRule<PMOAggVO> checkPlanPutNumRule = new PMOCheckPlanPutNumRule();
		processer.addBeforeRule(checkPlanPutNumRule);
		// (变更专用)当计划投入数量改小时，需保证不能小于max(订单各‘正常’类型工序的累计派工数量)
		IRule<PMOAggVO> checkDispatchNumRule = new PMOCheckDispatchNumRule();
		processer.addBeforeRule(checkDispatchNumRule);
		// （变更和修改共用）返工工序不可修改，并且最后一道返工工序必须是报告点；
		ICompareRule<PMOAggVO> procCheck = new PMORwkProcCheckRule();
		processer.addBeforeRule(procCheck);
		// 工序计划编辑性校验（有工序完工报告的工序及其之前的工序不可修改删除，也不可在其中插入工序）
		ICompareRule<PMOAggVO> putCheckRule = new PMOProcedurePutCheckRule();
		processer.addBeforeRule(putCheckRule);
		// 根据工序计划更新产品行计划完工时间
		IRule<PMOAggVO> filltimeprocedurerule = new PMOFillInsertPlanTimeByProcedureRule();
		processer.addBeforeRule(filltimeprocedurerule);
		// 日期是否符合自然逻辑顺序
		IRule<PMOAggVO> timeRule = new PMOCheckDateLogicRule();
		processer.addBeforeRule(timeRule);
		// 工序计划时间先后校验
		IRule<PMOAggVO> procdatelogicrule = new PMOCheckProcedureDateLogicRule(false);
		processer.addBeforeRule(procdatelogicrule);
		// 工序计划工序号重复校验
		IRule<PMOAggVO> proccoderule = new PMOCheckProcedureDupRule();
		processer.addBeforeRule(proccoderule);
		// 当计划投入数量改小时，需保证不能小于Max(生产订单工序计划中返工工序为‘否’的所有工序的累计完工数量【累计完工数量：工序对应的所有完工报告中该工序的完工数量】)
		IRule<PMOAggVO> planputNumberRule = new PMOCheckPlanPutNumberRule();
		processer.addBeforeRule(planputNumberRule);

		// （变更和修改共用）最后一条返工工序的工序转移方式不能为‘不转移’；
		IRule<PMOAggVO> rwkProcOperType = new PMORwkProcOperTypeRule();
		processer.addBeforeRule(rwkProcOperType);
		// 校验检测点必须是报告点,且转移方式不能为‘自动转移’
		IRule<PMOAggVO> chkPntRule = new PMOProcedureChkPntRule();
		processer.addBeforeRule(chkPntRule);
		// 增加工序计划必须有一个报告点 add lijjl
		processer.addBeforeRule(new PMOCheckProdurepointRule());
		// 非工序返工补单的保存校验，最后报告点的工序的工序转移方式必须为非转移
		IRule<PMOAggVO> operTypeRule = new PMOCheckApproveOperTypeRule();
		processer.addBeforeRule(operTypeRule);
		// 校验工序管理物料，工序计划不能为空
		IRule<PMOAggVO> approvecheckrule = new PMOCheckProcedureNotNullRule();
		processer.addBeforeRule(approvecheckrule);
		// 预计产出规则；
		ICompareRule<PMOAggVO> createOutput = new PMOIsCreatPlanOutputRule();
		processer.addBeforeRule(createOutput);

		// 批次号修改同步备料计划规则
		ICompareRule<PMOAggVO> batchcodeRule = new PMOBatchCodeEditSynPickmRule();
		processer.addBeforeRule(batchcodeRule);
		// 批次号修改同步批次档案规则
		ICompareRule<PMOAggVO> batchcodedocRule = new PMOBatchCodeEditRule();
		processer.addBeforeRule(batchcodedocRule);
		// 生成生产批次号
		IRule<PMOAggVO> fillbatchcodeRule = new PMOFillBatchCodeRule();
		processer.addBeforeRule(fillbatchcodeRule);
		// v636 序列号批次关联的不允许进行删除
		IRule<PMOAggVO> snBindRule = new PMOCheckSnBindRule();
		processer.addBeforeRule(snBindRule);
		// 更新前库存可用量规则
		IRule<PMOAggVO> checkATPUpdateRule = new PMOATPUpdateRule(true, PMOConst.PMO_BILLTYPE);
		processer.addBeforeRule(checkATPUpdateRule);
		// 回写生产报告数量
		ICompareRule<PMOAggVO> rewritewr = new RewriteUpdateNum4Renovate();
		processer.addBeforeRule(rewritewr);
		// 回写销售订单的累计补货数量
		ICompareRule<PMOAggVO> rewriteso = new RewriteUpdateNum4SO();
		processer.addBeforeRule(rewriteso);
		// 回写计划订单的排产数量
		ICompareRule<PMOAggVO> rewritepsm = new RewriteUpdateNum4PSM();
		processer.addBeforeRule(rewritepsm);
		// 回写主生产计划订单的已排产数量(根据订单类型)
		ICompareRule<PMOAggVO> rewritepo = new RewriteUpdateNum4MPS();
		processer.addBeforeRule(rewritepo);
		// 回写库存计划订单的已排产数量(根据订单类型)
		ICompareRule<PMOAggVO> rewriteinvp = new RewriteUpdateNum4INVP();
		processer.addBeforeRule(rewriteinvp);
		// 回写调拨订单的已排产数量(根据订单类型)
		ICompareRule<PMOAggVO> rewriteto = new RewriteUpdateNum4TO();
		processer.addBeforeRule(rewriteto);
		// 车间管理的工序完工会写返工数量
		ICompareRule<PMOAggVO> rewritesfc = new RewriteUpdateNum4SFC();
		processer.addBeforeRule(rewritesfc);
		// (变更专用)变更操作，生成新版本
		ICompareRule<PMOAggVO> verAutoUpRule = new PMOCreateVersionRule();
		processer.addBeforeRule(verAutoUpRule);

		// 调用库存接口，注册预留供给单据行数据
		ICompareRule<PMOAggVO> adjustReserveRule = new PMOAdjustReserveRule();
		processer.addBeforeRule(adjustReserveRule);

		// V65 回写收货单返工处理数量
		ICompareRule<PMOAggVO> rewritePSCrecive = new RewriteUpdateNum4PSCRecive();
		processer.addBeforeRule(rewritePSCrecive);
		// V65回写Wr返工订单的序列号使用标志
		IRule<PMOAggVO> wrMarkRule = new PMOMarkWrSNWhenUpdateRule();
		processer.addBeforeRule(wrMarkRule);
		// 65 特征码新增修改保存
		PMOCffileidInserAndUpdatetRule cffileidRule = new PMOCffileidInserAndUpdatetRule();
		processer.addBeforeRule(cffileidRule);
		// V65 检查数量与单位
		IRule<PMOAggVO> snCheckRule = new PMOCheckSNNumAndUnitRule();
		processer.addBeforeRule(snCheckRule);
		// 65 补充pk
		IRule<PMOAggVO> snRule = new PMOFillSNPkAndCodeRule();
		processer.addBeforeRule(snRule);
		// V65
		IRule<PMOAggVO> itemDeletesnRule = new PMOSyncSNWhenItemDeleteRule();
		processer.addBeforeRule(itemDeletesnRule);
		// V65
		ICompareRule<PMOAggVO> snSyncRule = new PMOSyncSNWhenUpdateRule();
		processer.addBeforeRule(snSyncRule);

	}

	private void addAfterRule(CompareAroundProcesser<PMOAggVO> processer) {
		// 回写返工的原始生产订单(根据来源订单表体id)
		ICompareRule<PMOAggVO> pmoBills = new RewriteUpdateNum4PMO();
		processer.addAfterRule(pmoBills);
		// （变更和修改通用）更新备料计划规则
		ICompareRule<PMOAggVO> pickmUpdateRule = new PMOUpdatePickmRule(this.checkInfoList);
		processer.addAfterRule(pickmUpdateRule);
		// 更新后库存可用量规则
		IRule<PMOAggVO> atpUpdateRule = new PMOATPUpdateRule(false, PMOConst.PMO_BILLTYPE);
		processer.addAfterRule(atpUpdateRule);
		// 修改保存即审核 added by fengjinga
		IRule<PMOAggVO> saveapproverule = new PMOUpdateSaveApproveRule();
		processer.addAfterRule(saveapproverule);

		//变更推送生产订单至锐制MES
		IRule<PMOAggVO> pushRZRule = new AfterApprovingSynchronizeRuleRZ(Boolean.FALSE);
		processer.addAfterFinalRule(pushRZRule);
	}

	// 挪退料建议
	private List<String> checkInfoList = new ArrayList<String>();

	public List<String> getCheckInfoList() {
		return this.checkInfoList;
	}

}
