package nc.bs.mmpac.pickm.bp;

import java.util.Map;

import nc.bs.mmpac.pickm.bp.rule.AfterupdateSyncEpicMesRule;
import nc.bs.mmpac.pickm.plugin.PickmPluginPoint;
import nc.bs.mmpac.pickm.rule.PickmCheckItemMaterialPermissionRule;
import nc.bs.mmpac.pickm.rule.PickmCheckMaterialPermissionRule;
import nc.bs.mmpac.pickm.rule.PickmCreateSubMoRule;
import nc.bs.mmpac.pickm.rule.PickmHeadEditRule;
import nc.bs.mmpac.pickm.rule.PickmItemAdjustRule;
import nc.bs.mmpac.pickm.rule.PickmItemReCreateRule;
import nc.bs.mmpac.pickm.rule.PickmNeedDeliverBackCheckRule;
import nc.bs.mmpac.pickm.rule.PickmReserveCheckForMoUpdateRule;
import nc.bs.mmpac.pickm.rule.PickmSubMoAdjustSuggestRule;
import nc.bs.mmpac.pickm.rule.PickmSynBrepairFlagRule;
import nc.bs.mmpac.pickm.rule.SNMaterialNotBackFlushRule;
import nc.bs.mmpac.pickm.rule.ic.PickmATPCheckRule;
import nc.bs.mmpac.pickm.rule.ic.PickmAutoChangeStateRule;
import nc.bs.mmpac.pickm.rule.ic.PickmAutoReserveRule;
import nc.bs.mmpac.pickm.rule.ic.PickmRewriteOtherNumRule;
import nc.bs.mmpac.pickm.rule.realsub.PickmRewritePLOWhenUpdateRule;
import nc.bs.mmpub.rule.MMAutoMaterialAssignRule;
import nc.bs.mmpub.rule.MMVOSagaFrozenValidateRule;
import nc.bs.pubapp.pub.rule.BillCodeCheckRule;
import nc.bs.pubapp.pub.rule.FieldLengthCheckRule;
import nc.bs.pubapp.pub.rule.FillUpdateDataRule;
import nc.bs.pubapp.pub.rule.OrgDisabledCheckRule;
import nc.bs.pubapp.pub.rule.UpdateBillCodeRule;
import nc.bs.uif2.validation.ValidationFailure;
import nc.bsutil.mmpac.pickm.PickmSagasUtil;
import nc.impl.pubapp.bd.material.assistant.MarAssistantSaveRule;
import nc.impl.pubapp.bd.userdef.UserDefSaveRule;
import nc.impl.pubapp.pattern.data.bill.template.UpdateBPTemplate;
import nc.impl.pubapp.pattern.rule.ICompareRule;
import nc.impl.pubapp.pattern.rule.IRule;
import nc.impl.pubapp.pattern.rule.processer.CompareAroundProcesser;
import nc.itf.org.IOrgConst;
import nc.util.mmf.busi.consts.BillTypeConst;
import nc.util.mmf.framework.base.MMValueCheck;
import nc.vo.mmpac.pickm.consts.PickmConsts;
import nc.vo.mmpac.pickm.entity.AggPickmVO;
import nc.vo.mmpac.pickm.entity.PickmHeadVO;
import nc.vo.mmpac.pickm.entity.PickmItemVO;
import nc.vo.mmpac.pickm.param.MoChangeParam;

/**
 * 生产订单修改后同步变更备料计划操作
 *
 * @author liddf
 * @version 2013-8-1 上午09:48:15
 * @since 6.31
 */
public class PickmUpdateForMOBP {
    // 挪退料建议
    private ValidationFailure checkInfo = new ValidationFailure();

    private AggPickmVO[] aggPickmVOArray;

    /**
     * 同步、变更、重算备料计划操作
     *
     * @param vos
     * @param paramMap
     */
    public String PickmUpdateForMO(AggPickmVO[] vos, Map<String, MoChangeParam> paramMap) {
        // 判空
        if (MMValueCheck.isEmpty(vos)) {
            return null;
        }
        // 获得修改前vo
        AggPickmVO[] originBills = new AggPickmVO[vos.length];
        for (int i = 0; i < vos.length; i++) {
            originBills[i] = (AggPickmVO) vos[i].clone();
        }
        // 缓存保存前全VO
        this.aggPickmVOArray = originBills.clone();
        // 创建数据模板BP
        UpdateBPTemplate<AggPickmVO> bp = new UpdateBPTemplate<AggPickmVO>(PickmPluginPoint.UPDATEFORMO);
        // 注入同步前规则
        this.addBeforeRule(bp.getAroundProcesser(), paramMap);
        // 注入同步后规则
        this.addAfterRule(bp.getAroundProcesser());
        // sagas 1 冻结并启用sagas，补偿
        PickmSagasUtil.addSagaAndCompensate4Update(vos, originBills);
        // MMSagasUtil.frozenAndAddSaga(vos,
        // MMPacBillTypeConstant.PICKM,MMSagasCompensateConst.COMPENSABLE,
        // null,PickmHeadVO.VBUSITYPE);

        // 执行新增操作
        bp.update(vos, originBills);
        // 挪料退料建议+配套子项建议
        return this.checkInfo.getMessage();
    }

    /**
     * 添加修改前规则
     *
     * @param aroundProcesser
     * @param paramMap
     */
    private void addBeforeRule(CompareAroundProcesser<AggPickmVO> aroundProcesser,
                               Map<String, MoChangeParam> paramMap) {
        // sagas 冻结校验
        IRule<AggPickmVO> sagasCheckrule = new MMVOSagaFrozenValidateRule<AggPickmVO>(true);
        aroundProcesser.addBeforeRule(sagasCheckrule);
        // 备料计划表头同步rule
        IRule<AggPickmVO> pickmHeadEditRule = new PickmHeadEditRule(paramMap);
        aroundProcesser.addBeforeRule(pickmHeadEditRule);
        // 备料计划表体重算rule
        IRule<AggPickmVO> pickmItemReCreateRule = new PickmItemReCreateRule(paramMap, true);
        aroundProcesser.addBeforeRule(pickmItemReCreateRule);
        // 备料计划变更rule
        IRule<AggPickmVO> pickmItemAdjustRule = new PickmItemAdjustRule(paramMap);
        aroundProcesser.addBeforeRule(pickmItemAdjustRule);
        // 校验是否有预留数量（变更后计划出库数量小于预留数量+累计实收数量报错，重算后维度变化则清除预留）
        IRule<AggPickmVO> pickmCheckReservetRule = new PickmReserveCheckForMoUpdateRule(paramMap);
        aroundProcesser.addBeforeRule(pickmCheckReservetRule);
        // 校验组织是否已停用
        IRule<AggPickmVO> orgRule = new OrgDisabledCheckRule(IOrgConst.PK_ORG, IOrgConst.FACTORYTYPE);
        aroundProcesser.addBeforeRule(orgRule);
        // 修改保存时的数据补充规则
        IRule<AggPickmVO> fillDataRule = new FillUpdateDataRule();
        aroundProcesser.addBeforeRule(fillDataRule);

        // 表头物料自动分配
        // IRule<AggPickmVO> autoHMaterialAssignRule = new
        // MMAutoMaterialAssignRule<AggPickmVO>(PickmHeadVO.CMATERIALVID,
        // null, new String[] { PickmHeadVO.PK_ORG }, null);
        // aroundProcesser.addBeforeFinalRule(autoHMaterialAssignRule);
        // 表体物料自动分配
        IRule<AggPickmVO> autobMaterialAssignRule = new MMAutoMaterialAssignRule<AggPickmVO>(null,
                PickmItemVO.CBMATERIALVID, new String[]{PickmHeadVO.PK_ORG},
                new String[]{PickmItemVO.CDELIVERORGID, PickmItemVO.CSUPPLYORGID});
        aroundProcesser.addBeforeFinalRule(autobMaterialAssignRule);

        // 物料合法性校验规则
        IRule<AggPickmVO> marperRule = new PickmCheckMaterialPermissionRule();
        aroundProcesser.addBeforeRule(marperRule);

        // 子项物料发料组织合法性校验规则
        IRule<AggPickmVO> bmarperRule = new PickmCheckItemMaterialPermissionRule();
        aroundProcesser.addBeforeRule(bmarperRule);
        // 进行序列号管理的物料不能设置为倒冲和交互式倒冲
        IRule<AggPickmVO> snMaterialCheckRule = new SNMaterialNotBackFlushRule();
        aroundProcesser.addBeforeRule(snMaterialCheckRule);
        // 校验备料计划倒冲时机
//		IRule<AggPickmVO> checkFbackFlusTime = new PickmFbackflustimeCheckRule();
//		aroundProcesser.addBeforeRule(checkFbackFlusTime);
        // 单据字段长度检查规则
        IRule<AggPickmVO> lengthCheckRule = new FieldLengthCheckRule();
        aroundProcesser.addBeforeRule(lengthCheckRule);

        // 自由辅助属性检查的规则
        MarAssistantSaveRule<AggPickmVO> marRule = new MarAssistantSaveRule<AggPickmVO>();
        // marRule.setNotNullValidate(PickmConsts.CMATERIAL_VID_NAME);
        marRule.setPos(0);
        aroundProcesser.addBeforeRule(marRule);
        // 自由辅助属性检查的规则
        MarAssistantSaveRule<AggPickmVO> bmarRule = new MarAssistantSaveRule<AggPickmVO>();
        // bmarRule.setNotNullValidate(PickmItemVO.CBMATERIALVID);
        bmarRule.setPos(1);
        aroundProcesser.addBeforeRule(bmarRule);

        // 自定义项检查的规则
        // UserDefSaveRule<AggPickmVO> defRule = new UserDefSaveRule<AggPickmVO>(new
        // Class[] {
        // PickmHeadVO.class, PickmItemVO.class
        // });
        // aroundProcesser.addBeforeRule(defRule);
        // 更新单据号的规则
        ICompareRule<AggPickmVO> updateBillCodeRule = new UpdateBillCodeRule(BillTypeConst.PICKM,
                PickmConsts.VBILL_CODE_NAME, IOrgConst.PK_GROUP, IOrgConst.PK_ORG);
        aroundProcesser.addBeforeRule(updateBillCodeRule);

        // 备料计划ATP检查规则
        IRule<AggPickmVO> pickmATPCheckRule = new PickmATPCheckRule(true, null);
        aroundProcesser.addBeforeRule(pickmATPCheckRule);
        // 检查自定义项数据数据类型和自定义项类型是否一致规则
        IRule<AggPickmVO> userDefSaveRule = new UserDefSaveRule<AggPickmVO>(new String[]{"vdef", "vbdef"},
                new Class[]{PickmHeadVO.class, PickmItemVO.class});
        aroundProcesser.addBeforeRule(userDefSaveRule);
        // 进行成套数量、累计超额数量等联动值的重算
        PickmRewriteOtherNumRule setPartsRule = new PickmRewriteOtherNumRule();
        aroundProcesser.addBeforeRule(setPartsRule);

        // 调用更新状态rule:自动完成 or 自动取消完成
        ICompareRule<AggPickmVO> autoChangeStateRule = new PickmAutoChangeStateRule();
        aroundProcesser.addBeforeRule(autoChangeStateRule);
    }

    /**
     * 添加修改后规则
     *
     * @param aroundProcesser
     */
    private void addAfterRule(CompareAroundProcesser<AggPickmVO> aroundProcesser) {
        // 保存单据号唯一性校验规则
        IRule<AggPickmVO> billCodeCheckRule = new BillCodeCheckRule(BillTypeConst.PICKM, PickmConsts.VBILL_CODE_NAME,
                IOrgConst.PK_GROUP, IOrgConst.PK_ORG);
        aroundProcesser.addAfterRule(billCodeCheckRule);

        // 备料计划ATP检查规则
        IRule<AggPickmVO> pickmATPCheckRule = new PickmATPCheckRule(false, this.aggPickmVOArray);
        aroundProcesser.addAfterRule(pickmATPCheckRule);

        // 自动预留规则
        IRule<AggPickmVO> pickmAutoReserveRule = new PickmAutoReserveRule();
        aroundProcesser.addAfterRule(pickmAutoReserveRule);

        // 回写实际替代表规则
        ICompareRule<AggPickmVO> pickmRewritePLOWhenUpdateRule = new PickmRewritePLOWhenUpdateRule();
        aroundProcesser.addAfterRule(pickmRewritePLOWhenUpdateRule);
        // 同步返修标识规则
        IRule<AggPickmVO> synBrepairRule = new PickmSynBrepairFlagRule();
        aroundProcesser.addAfterRule(synBrepairRule);
        // 母订单备料计划保存时生成子订单
        IRule<AggPickmVO> pickmCreateSubMoRule = new PickmCreateSubMoRule();
        aroundProcesser.addAfterRule(pickmCreateSubMoRule);
        // 挪料/判断规则
        IRule<AggPickmVO> deliverBackInfoRule = new PickmNeedDeliverBackCheckRule(this.checkInfo);
        aroundProcesser.addAfterRule(deliverBackInfoRule);
        // 配套变更建议
        ICompareRule<AggPickmVO> subMoAdjustSuggestRule = new PickmSubMoAdjustSuggestRule(this.checkInfo);
        aroundProcesser.addAfterRule(subMoAdjustSuggestRule);


        aroundProcesser.addAfterRule(new AfterupdateSyncEpicMesRule());
    }

}
