package nc.bs.ic.general.rule.before;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import nc.bs.framework.common.NCLocator;
import nc.bs.ic.pub.base.ICRule;
import nc.bs.ic.pub.db.ICDBVisitor;
import nc.bs.ic.pub.env.ICBSContext;
import nc.impl.pubapp.pattern.rule.ICompareRule;
import nc.itf.ic.batch.IBatchCheck;
import nc.itf.ic.batch.IBatchGenerate;
import nc.pubitf.scmf.ic.mbatchcode.IBatchcodePubService;
import nc.vo.ic.batch.AbstractBillItemAdapter;
import nc.vo.ic.batch.ICBillBodyAdapter;
import nc.vo.ic.batchcode.BatchSynchronizer;
import nc.vo.ic.batchcode.ICBatchFields;
import nc.vo.ic.general.define.ICBillBodyVO;
import nc.vo.ic.general.define.ICBillVO;
import nc.vo.ic.general.define.InOutFlag;
import nc.vo.ic.general.util.InOutHelp;
import nc.vo.ic.pub.lang.BatchRes;
import nc.vo.ic.pub.lang.ResBase;
import nc.vo.ic.pub.util.NCBaseTypeUtils;
import nc.vo.ic.pub.util.StringUtil;
import nc.vo.ic.pub.util.VOEntityUtil;
import nc.vo.ic.pub.util.ValueCheckUtil;
import nc.vo.pub.BusinessException;
import nc.vo.pub.JavaType;
import nc.vo.pub.VOStatus;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nc.vo.scmf.ic.mbatchcode.BatchcodeVO;
import nc.vo.scmpub.res.billtype.ICBillType;

/**
 * 
 * @description 批次属性检查，例如失效日期等 存货是否是批次管理，如果是则批次号不为空，如空报错
 *              存货是否保质期管理，如果是，则生产日期不空，如空报错
 *              如果生产日期不空并且失效日期为空，(则后台自动补全失效日期，暂不实现，推单时需要补全) 进行失效日期和生产日期验证
 *              针对出库行进行批次档案的存在性检查
 *              将界面的批次信息根据批次档案进行补全并缓存至Session，如果界面的批次字段有改动，不覆盖改动。 根据表体新增批次号
 * 
 * @scene 批次属性检查 针对出库行进行批次档案的存在性检查 根据表体新增批次号
 * @param 无
 *
 * @since 6.3
 * @version 2010-5-20 下午03:43:09
 * @author chennn
 */
public class BatchAttributeCheck<E extends ICBillVO> extends ICRule<E> implements ICompareRule<E> {

	@Override
	public void process(E[] vos) {
		try {
			List<BatchcodeVO> batches = new ArrayList<BatchcodeVO>();
			Map<String, String> newBatchMap = new HashMap<String, String>();
			this.checkAttribute(vos);
			this.reSignBatchcode(vos);
			for (E vo : vos) {
				this.handleOutBatch(vo);
			}
			newBatchMap = this.processNewBatch(vos);
			batches = this.getBatch(vos);

			new ICBSContext().setICBatchBefore(batches);
			new ICBSContext().setNewBatchMap(newBatchMap);
		} catch (BusinessException ex) {
			ExceptionUtils.wrappException(ex);
		}
	}

	@Override
	public void process(E[] vos, E[] originvos) {
		try {
			List<BatchcodeVO> batches = new ArrayList<BatchcodeVO>();
			Map<String, String> newBatchMap = new HashMap<String, String>();

			this.checkAttribute(vos);
			this.reSignBatchcode(vos);
			for (E vo : vos) {
				this.handleOutBatch(vo);
			}
			newBatchMap = this.processNewBatch(vos);
			batches = this.getBatch(originvos);

			new ICBSContext().setICBatchBefore(batches);
			new ICBSContext().setNewBatchMap(newBatchMap);
		} catch (BusinessException ex) {
			ExceptionUtils.wrappException(ex);
		}
	}

	protected void checkAttribute(E[] bills) {
		try {
			NCLocator.getInstance().lookup(IBatchCheck.class).checkBatchAttribute(bills);
//      for (E bill : bills) {
//        if (bill == null || bill.getBodys() == null) {
//          return;
//        }
//        NCLocator.getInstance().lookup(IBatchCheck.class).checkBatchAttribute(
//            bill);
//      }
		} catch (BusinessException ex) {
			ExceptionUtils.wrappException(ex);
		}
	}

	/**
	 * 录入批次号后，批次主键为空的情况下，重新查询批次档案后并对批次主键重新赋值 （物料+批次号重复）
	 * 
	 * @param bills
	 */
	private void reSignBatchcode(E[] bills) {
		List<String> lvids = new ArrayList<String>();
		List<String> lbatchcodes = new ArrayList<String>();
		for (E bill : bills) {
			for (ICBillBodyVO bvo : bill.getBodys()) {
				if (!StringUtil.isSEmptyOrNull(bvo.getCmaterialvid())
						&& !StringUtil.isSEmptyOrNull(bvo.getVbatchcode())) {
					lvids.add(bvo.getCmaterialvid());
					lbatchcodes.add(bvo.getVbatchcode());
				}
			}
		}
		if (!ValueCheckUtil.isNullORZeroLength(lvids)) {
			try {
				BatchcodeVO[] batchvos = NCLocator.getInstance().lookup(IBatchcodePubService.class).queryBatchVOs(
						lvids.toArray(new String[lvids.size()]), lbatchcodes.toArray(new String[lbatchcodes.size()]));
				if (ValueCheckUtil.isNullORZeroLength(batchvos))
					return;

				Map<String, BatchcodeVO> hsret = new HashMap<String, BatchcodeVO>();
				String keyvalue = null;
				for (BatchcodeVO vo : batchvos) {
					keyvalue = vo.getCmaterialvid() + vo.getVbatchcode();
					hsret.put(keyvalue, vo);
				}
				for (E bill : bills) {
					for (ICBillBodyVO bvo : bill.getBodys()) {
						if (!StringUtil.isSEmptyOrNull(bvo.getCmaterialvid())
								&& !StringUtil.isSEmptyOrNull(bvo.getVbatchcode())
								&& StringUtil.isSEmptyOrNull(bvo.getPk_batchcode())) {
							BatchcodeVO batchvo = hsret.get(bvo.getCmaterialvid() + bvo.getVbatchcode());
							if (null == batchvo)
								continue;
							bvo.setPk_batchcode(batchvo.getPk_batchcode());
						}
					}
				}
			} catch (BusinessException e) {
				ExceptionUtils.wrappException(e);
			}
		}
	}

	/**
	 * 根据pk_batchcode取批次档案信息
	 * 
	 * @param pk_batchcodes
	 * @return
	 * @since 6.0
	 */
	private Map<String, Object[]> fetchBatchByPks(List<String> pk_batchcodes, String[] selectFields) {

		BatchcodeVO batchvo = new BatchcodeVO();
		String tablename = batchvo.getMetaData().getPrimaryAttribute().getColumn().getTable().getName();
		JavaType[] types = VOEntityUtil.getDBFieldJavaType(batchvo.getMetaData(), selectFields)
				.toArray(new JavaType[selectFields.length]);
		return new ICDBVisitor().getValues(tablename, selectFields, types, BatchcodeVO.PK_BATCHCODE,
				pk_batchcodes.toArray(new String[pk_batchcodes.size()]), tablename + ".dr=0");

	}

	private List<BatchcodeVO> getBatch(E[] vos) {
		try {
			List<BatchcodeVO> retList = new ArrayList<BatchcodeVO>();
			BatchSynchronizer syn = new BatchSynchronizer(new ICBatchFields());
			for (E vo : vos) {
				for (ICBillBodyVO body : vo.getBodys()) {
					if (StringUtil.isSEmptyOrNull(body.getPk_batchcode())
							&& StringUtil.isSEmptyOrNull(body.getVbatchcode())) {
						continue;
					}
					BatchcodeVO batch = new BatchcodeVO();
					syn.synBilltoBatchVO(body, batch);
					retList.add(batch);
				}
			}
			if (retList.size() <= 0) {
				return retList;
			}
			String[] pk_batchcodes = VOEntityUtil.getVOsValues(retList.toArray(new BatchcodeVO[retList.size()]),
					BatchcodeVO.PK_BATCHCODE, String.class);
			BatchcodeVO[] retVOs = NCLocator.getInstance().lookup(IBatchcodePubService.class)
					.queryBatchcodesByPks(pk_batchcodes);
			return Arrays.asList(retVOs);
		} catch (BusinessException ex) {
			ExceptionUtils.wrappException(ex);
			return null;
		}
	}

	/**
	 * 处理出库的批次，进行批次检查，批次不存在则保错 返回存在批次号的入库表体
	 * 
	 * @param bill
	 * @since 6.0
	 */
	private List<Integer> handleOutBatch(E bill) {

		ICBillType billType = bill.getHead().getBillType();
		StringBuilder errString = null;
		List<String> batchCodes = new ArrayList<String>();
		List<String> crowNo = new ArrayList<String>();
		List<Integer> retIndex = new ArrayList<Integer>();
		List<String> pk_batchcodes = new ArrayList<String>();
		for (int i = 0; i < bill.getBodys().length; i++) {
			ICBillBodyVO bodyVO = bill.getBody(i);
			if (StringUtil.isSEmptyOrNull(bodyVO.getVbatchcode()) || bodyVO.getStatus() == VOStatus.DELETED) {
				continue;
			}
			if (InOutHelp.getRealInOutFlag(billType, bodyVO) == InOutFlag.Out) {
				if (StringUtil.isSEmptyOrNull(bodyVO.getPk_batchcode())) {
					this.showErr(errString, bodyVO.getCrowno(), bodyVO.getVbatchcode());
				} else {
					batchCodes.add(bodyVO.getVbatchcode());
					pk_batchcodes.add(bodyVO.getPk_batchcode());
					crowNo.add(bodyVO.getCrowno());
				}
				continue;
			} else if (InOutHelp.getRealInOutFlag(billType, bodyVO) == InOutFlag.In) {// 存在实际入库的表体才进行处理
				retIndex.add(Integer.valueOf(i));
			}
		}
		if (pk_batchcodes.size() == 0) {
			return retIndex;
		}
//add by wangwei
//    Map<String, Object[]> batchVO =
//        this.fetchBatchByPks(pk_batchcodes, new String[] {
//          BatchcodeVO.TS
//        });
//    for (int i = 0; i < pk_batchcodes.size(); i++) {
//      if (!batchVO.containsKey(pk_batchcodes.get(i))) {
//        this.showErr(errString, crowNo.get(i), batchCodes.get(i));
//      }
//    }
		return retIndex;
	}

	/*
	 * 仅仅处理新增的批次，将新增的批次保存到数据库，同时回填单据上的批次pk
	 */
	private Map<String, String> processNewBatch(E[] bills) throws BusinessException {
		List<AbstractBillItemAdapter> itemInfos = new ArrayList<AbstractBillItemAdapter>();
		for (E bill : bills) {
			for (ICBillBodyVO body : bill.getBodys()) {
				if (StringUtil.isSEmptyOrNull(body.getPk_batchcode())
						&& !StringUtil.isSEmptyOrNull(body.getVbatchcode()) && body.getStatus() != VOStatus.DELETED) {
					// 新增批次时默认单据入库日期为首次入库日期
					if (NCBaseTypeUtils.isNull(body.getDinbounddate())) {
						body.setDinbounddate(body.getDbizdate());
					}
					AbstractBillItemAdapter batchInfo = new ICBillBodyAdapter(body);
					itemInfos.add(batchInfo);
				}
			}
		}
		List<BatchcodeVO> batchcodes = NCLocator.getInstance().lookup(IBatchGenerate.class)
				.insertBatchWithoutSource(itemInfos, new ICBatchFields());
		Map<String, String> batchtoPks = new HashMap<String, String>();
		if (batchcodes != null && batchcodes.size() > 0) {
			BatchSynchronizer syn = new BatchSynchronizer(new ICBatchFields());
			syn.setBatchtoBill(batchcodes.toArray(new BatchcodeVO[batchcodes.size()]),
					itemInfos.toArray(new AbstractBillItemAdapter[itemInfos.size()]));// 同步时回填批次PK
			for (BatchcodeVO vo : batchcodes) {
				String key = StringUtil.mergeString(
						VOEntityUtil.getVOValues(vo, new String[] { BatchcodeVO.CMATERIALVID, BatchcodeVO.VBATCHCODE }),
						null, null);
				batchtoPks.put(key, vo.getPk_batchcode());
			}
		}
		return batchtoPks;
	}

	/**
	 * 根据行号和批次号给出出错提示
	 * 
	 * @param errString
	 * @param crowno
	 * @param batchcode
	 * @since 6.0
	 */
	private void showErr(StringBuilder errString, String crowno, String batchcode) {

		if (errString == null) {
			errString = new StringBuilder();
		}
		errString.append(BatchRes.getBatchNotExsitErr());
		errString.append(ResBase.getCrowno() + crowno);
		errString.append(ResBase.getVbatchcode() + batchcode);
	}

}
