package nc.bs.mmpac.pickm.bp;

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

import nc.bs.mmpac.pickm.bp.rule.AfterupdateSyncEpicMesRule;
import nc.bs.mmpac.pickm.plugin.PickmPluginPoint;
import nc.bs.mmpac.pickm.rule.PSCPickmRewriteMoPickmUpdateRule;
import nc.bs.mmpac.pickm.rule.PickmAutoApproveAfterSaveRule;
import nc.bs.mmpac.pickm.rule.PickmBillStatusToFreeRule;
import nc.bs.mmpac.pickm.rule.PickmCheckItemMaterialPermissionRule;
import nc.bs.mmpac.pickm.rule.PickmCheckMaterialPermissionRule;
import nc.bs.mmpac.pickm.rule.PickmCheckRowNOChangedRule;
import nc.bs.mmpac.pickm.rule.PickmCheckSameStockRule;
import nc.bs.mmpac.pickm.rule.PickmCreateSubMoRule;
import nc.bs.mmpac.pickm.rule.PickmFbackflustimeCheckRule;
import nc.bs.mmpac.pickm.rule.PickmItemVOFilterRule;
import nc.bs.mmpac.pickm.rule.PickmNeedDeliverBackCheckRule;
import nc.bs.mmpac.pickm.rule.PickmRowNoRule;
import nc.bs.mmpac.pickm.rule.PickmSaveRule;
import nc.bs.mmpac.pickm.rule.PickmSubMoAdjustSuggestRule;
import nc.bs.mmpac.pickm.rule.SNMaterialNotBackFlushRule;
import nc.bs.mmpac.pickm.rule.ic.PickmATPCheckRule;
import nc.bs.mmpac.pickm.rule.ic.PickmAdjustReserveWhenEditRule;
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.MMATOMaterialCheckRule;
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.data.bill.tool.BillTransferTool;
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.pub.VOStatus;

/**
 * 备料计划修改 BP
 */
public class PickmUpdateBP {

    private AggPickmVO[] aggPickmVOArray;

    private UpdateBPTemplate<AggPickmVO> bp;

    private boolean isCreateSub;

    private boolean isForYL;
    private boolean isForNcc = false;
    ;


    // 挪退料建议
    private ValidationFailure checkInfo = new ValidationFailure();

    public PickmUpdateBP() {
        this.bp = new UpdateBPTemplate<AggPickmVO>(PickmPluginPoint.UPDATE);
    }

    public PickmUpdateBP(boolean isForNcc) {
        this.bp = new UpdateBPTemplate<AggPickmVO>(PickmPluginPoint.UPDATE);
        this.isForNcc = isForNcc;
    }

    public CompareAroundProcesser<AggPickmVO> getAroundProcesser() {
        return this.bp.getAroundProcesser();
    }

    public AggPickmVO[] update(AggPickmVO[] vos, boolean isYL, boolean isForCereateSub) {

        if (MMValueCheck.isEmpty(vos)) {
            return null;
        }
        for (AggPickmVO vo : vos) {
            vo.getParentVO().setStatus(VOStatus.UPDATED);
            PickmItemVO[] bvos = (PickmItemVO[]) vo.getChildrenVO();
            for (PickmItemVO bvo : bvos) {
                if (MMValueCheck.isNotEmpty(bvo.getCpickm_bid()) && bvo.getStatus() != VOStatus.NEW
                        && bvo.getStatus() != VOStatus.DELETED) {
                    bvo.setStatus(VOStatus.UPDATED);
                }
                // 解决修改备料计划，新增行时，平台NCLocator功能在2004版本赋值外键丢失了对应的赋值关系，特在此次补值；
                if (bvo.getStatus() == VOStatus.NEW) {
                    bvo.setCpickmid(vo.getParentVO().getCpickmid());
                }
            }
        }

        this.isForYL = isYL;
        this.isCreateSub = isForCereateSub;

        // 加锁 + 检查ts
        BillTransferTool<AggPickmVO> transTool = new BillTransferTool<AggPickmVO>(vos);

        // 补全前台VO
        AggPickmVO[] fullBills = transTool.getClientFullInfoBill();

        // 缓存保存前全VO
        this.aggPickmVOArray = fullBills.clone();

        // 获得修改前vo
        AggPickmVO[] originBills = transTool.getOriginBills();
        // 添加保存前规则
        this.addBeforeRule(this.bp.getAroundProcesser());

        // 添加保存后规则
        this.addAfterRule(this.bp.getAroundProcesser());
        // 冻结 补偿
        PickmSagasUtil.addSagaAndCompensate4Update(fullBills, originBills);

        // 执行保存操作
        AggPickmVO[] retBills = this.bp.update(fullBills, originBills);
        // 构造返回数据
        AggPickmVO[] rstbills = this.getReturnvo(retBills);
        // if (!this.isCreateSub) {
        //
        // rstbills = transTool.getBillForToClient(retBills);
        // }
        rstbills[0].getParentVO().setCheckInfo(this.checkInfo.getMessage());
        return rstbills;
    }

    private AggPickmVO[] getReturnvo(AggPickmVO[] retBills) {
        if (MMValueCheck.isEmpty(retBills)) {
            return null;
        }
        for (AggPickmVO agg : retBills) {
            if (MMValueCheck.isEmpty(agg.getChildrenVO())) {
                continue;
            }
            List<PickmItemVO> items = new ArrayList<PickmItemVO>();
            for (PickmItemVO item : (PickmItemVO[]) agg.getChildrenVO()) {
                if (item.getStatus() != VOStatus.DELETED) {
                    items.add(item);
                }
            }
            if (MMValueCheck.isNotEmpty(items)) {
                agg.setChildrenVO(items.toArray(new PickmItemVO[0]));
            }

        }
        return retBills;
    }

    /**
     * 修改后规则
     *
     * @param processor
     */
    @SuppressWarnings({
            "unchecked"
    })
    private void addAfterRule(CompareAroundProcesser<AggPickmVO> processer) {

        // 保存单据号唯一性校验规则
        IRule<AggPickmVO> billCodeCheckRule =
                new BillCodeCheckRule(BillTypeConst.PICKM, PickmConsts.VBILL_CODE_NAME, IOrgConst.PK_GROUP,
                        IOrgConst.PK_ORG);
        processer.addAfterRule(billCodeCheckRule);

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

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

        // 回写实际替代表规则
        ICompareRule<AggPickmVO> pickmRewritePLOWhenUpdateRule = new PickmRewritePLOWhenUpdateRule();
        processer.addAfterRule(pickmRewritePLOWhenUpdateRule);
        if (this.isForNcc) {
            // ncc2012 sagas修改
            IRule<AggPickmVO> pickmAutoApproveRule = new PickmAutoApproveAfterSaveRule(this.isForNcc);
            processer.addAfterRule(pickmAutoApproveRule);
        }
        // 母订单备料计划保存时生成子订单
        IRule<AggPickmVO> pickmCreateSubMoRule = new PickmCreateSubMoRule();
        processer.addAfterRule(pickmCreateSubMoRule);
        // 回写来源备料计划（工序委外备料计划）
        ICompareRule<AggPickmVO> psPickmRewriteRule = new PSCPickmRewriteMoPickmUpdateRule();
        processer.addBeforeRule(psPickmRewriteRule);
        // 挪料/判断规则
        IRule<AggPickmVO> deliverBackInfoRule = new PickmNeedDeliverBackCheckRule(this.checkInfo);
        processer.addAfterRule(deliverBackInfoRule);
        // 配套变更建议
        ICompareRule<AggPickmVO> subMoAdjustSuggestRule = new PickmSubMoAdjustSuggestRule(this.checkInfo);
        processer.addAfterRule(subMoAdjustSuggestRule);
        processer.addAfterRule(new AfterupdateSyncEpicMesRule());
    }

    /**
     * 修改前规则
     *
     * @param processor
     */

    @SuppressWarnings("unchecked")
    private void addBeforeRule(CompareAroundProcesser<AggPickmVO> processer) {

        // 清除空的表体行 
        IRule<AggPickmVO> filterRule = new PickmItemVOFilterRule();
        processer.addBeforeRule(filterRule);
        // 校验组织是否已停用
        IRule<AggPickmVO> orgRule = new OrgDisabledCheckRule(IOrgConst.PK_ORG, IOrgConst.FACTORYTYPE);
        processer.addBeforeRule(orgRule);
        // sagas 冻结校验
        IRule<AggPickmVO> sagasCheckrule = new MMVOSagaFrozenValidateRule<AggPickmVO>(true);
        processer.addBeforeRule(sagasCheckrule);
        // 产品为ATO选配件，验证子项配置码是否为空
        IRule<AggPickmVO> mmatoMaterialCheckRule = new MMATOMaterialCheckRule(PickmHeadVO.CMATERIALVID, null, PickmHeadVO.CFFILEID);
        processer.addBeforeRule(mmatoMaterialCheckRule);
        // 校验是否存在相同行号
        IRule<AggPickmVO> checkSameRow = new PickmRowNoRule();
        processer.addBeforeRule(checkSameRow);
        // 进行序列号管理的物料不能设置为倒冲和交互式倒冲
        IRule<AggPickmVO> snMaterialCheckRule = new SNMaterialNotBackFlushRule();
        processer.addBeforeRule(snMaterialCheckRule);
        // 校验备料计划倒冲时机
        IRule<AggPickmVO> checkFbackFlusTime = new PickmFbackflustimeCheckRule();
        processer.addBeforeRule(checkFbackFlusTime);

        // 修改保存时的数据补充规则
        IRule<AggPickmVO> fillDataRule = new FillUpdateDataRule();
        processer.addBeforeRule(fillDataRule);

        // 校验供应仓库和发料仓库不能相同
        IRule<AggPickmVO> sameRule = new PickmCheckSameStockRule();
        processer.addBeforeRule(sameRule);

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

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

        // 子项物料发料组织合法性校验规则
        IRule<AggPickmVO> bmarperRule = new PickmCheckItemMaterialPermissionRule();
        processer.addBeforeRule(bmarperRule);

        // 单据字段长度检查规则
        IRule<AggPickmVO> lengthCheckRule = new FieldLengthCheckRule();
        processer.addBeforeRule(lengthCheckRule);

        // 自由辅助属性检查的规则
        MarAssistantSaveRule<AggPickmVO> marRule = new MarAssistantSaveRule<AggPickmVO>();
        // marRule.setNotNullValidate(PickmConsts.CMATERIAL_VID_NAME);
        marRule.setPos(0);
        processer.addBeforeRule(marRule);
        // 自由辅助属性检查的规则
        MarAssistantSaveRule<AggPickmVO> bmarRule = new MarAssistantSaveRule<AggPickmVO>();
        // bmarRule.setNotNullValidate(PickmItemVO.CBMATERIALVID);
        bmarRule.setPos(1);
        processer.addBeforeRule(bmarRule);
        // 自定义项检查的规则
        UserDefSaveRule<AggPickmVO> defRule = new UserDefSaveRule<AggPickmVO>(new Class[]{
                PickmHeadVO.class, PickmItemVO.class
        });
        processer.addBeforeRule(defRule);

        // 备料计划保存规则
        IRule<AggPickmVO> pickmSaveRule = new PickmSaveRule();
        processer.addBeforeRule(pickmSaveRule);
        // 将状态由审批不通过修改为自由
        IRule<AggPickmVO> billstatusRule = new PickmBillStatusToFreeRule();
        processer.addBeforeRule(billstatusRule);
        // 存在下游子订单的，备料计划不允许修改单据号和行号
        ICompareRule<AggPickmVO> checkRowRule = new PickmCheckRowNOChangedRule();
        processer.addBeforeRule(checkRowRule);
        // 更新单据号的规则
        ICompareRule<AggPickmVO> updateBillCodeRule =
                new UpdateBillCodeRule(BillTypeConst.PICKM, PickmConsts.VBILL_CODE_NAME, IOrgConst.PK_GROUP,
                        IOrgConst.PK_ORG);
        processer.addBeforeRule(updateBillCodeRule);

        // 备料计划ATP检查规则
        IRule<AggPickmVO> pickmATPCheckRule = new PickmATPCheckRule(true, null);
        processer.addBeforeRule(pickmATPCheckRule);

        if (this.isForYL) {
            // 修改保存前解除预留规则
            ICompareRule<AggPickmVO> pickmUnPSForEditRule = new PickmAdjustReserveWhenEditRule();
            processer.addBeforeRule(pickmUnPSForEditRule);
        }

        // 检查自定义项数据数据类型和自定义项类型是否一致规则
        IRule<AggPickmVO> userDefSaveRule = new UserDefSaveRule<AggPickmVO>(new String[]{
                "vdef", "vbdef"
        }, new Class[]{
                PickmHeadVO.class, PickmItemVO.class
        });
        processer.addBeforeRule(userDefSaveRule);
        // 进行成套数量、累计超额数量等联动值的重算
        PickmRewriteOtherNumRule setPartsRule = new PickmRewriteOtherNumRule();
        processer.addBeforeRule(setPartsRule);
        // 调用更新状态rule:自动完成 or 自动取消完成
        ICompareRule<AggPickmVO> autoChangeStateRule = new PickmAutoChangeStateRule();
        processer.addBeforeRule(autoChangeStateRule);

    }
}
