package nc.vo.ic.m4n.entity.deal;

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

import nc.bs.dao.BaseDAO;
import nc.bs.dao.DAOException;
import nc.bs.ic.general.util.RuleUtils;
import nc.bs.ic.pub.env.ICBSContext;
import nc.vo.bd.material.stock.MaterialStockVO;
import nc.vo.ic.invadjust.lang.InvAdjustRes;
import nc.vo.ic.m4n.entity.TransformBodyVO;
import nc.vo.ic.m4n.entity.TransformRowFlag;
import nc.vo.ic.m4n.entity.TransformVO;
import nc.vo.ic.pub.define.ICPubMetaNameConst;
import nc.vo.ic.pub.util.CollectionUtils;
import nc.vo.ic.pub.util.StringUtil;
import nc.vo.ic.pub.util.VOEntityUtil;
import nc.vo.ic.special.check.SpecialBillEntityCheck;
import nc.vo.pub.BusinessException;
import nc.vo.pub.VOStatus;
import nc.vo.pub.lang.UFBoolean;

/**
 * <p>
 * <b>本类主要完成以下功能：</b> 形态转换数据校验 1.行类型校验 2.转换前后的物料维度校验 3.必输项及数量、主数量非空校验 限BS端调用
 * 
 * <ul>
 * <li>
 * </ul>
 * <p>
 * <p>
 * 
 * @version 6.0
 * @since 6.0
 * @author chennn
 * @time 2010-5-31 下午04:35:35
 */
public class TransformVOChecker {

	public void checkNullItem(TransformVO bill) throws BusinessException {

		new SpecialBillEntityCheck().checkNullItem(bill);
		List<String> errVendorRows = new ArrayList<String>();// 供应商
		List<String> errProductRows = new ArrayList<String>();// 生产厂商
		List<String> errProjectRows = new ArrayList<String>();// 项目
		List<String> errCffileidRows = new ArrayList<String>();// 特征码
		List<String> errStateRows = new ArrayList<String>();
		List<String> errNumRows = new ArrayList<String>();// 数量和主数量
		List<String> errCasscustRows = new ArrayList<String>();
		ICBSContext context = new ICBSContext();
		for (TransformBodyVO body : bill.getBodys()) {
			// 过滤已经删除或者没有修改的表体行
			if (body.getStatus() == VOStatus.DELETED || body.getStatus() == VOStatus.UNCHANGED) {
				continue;
			}
			String cmaterialvid = body.getCmaterialvid();
			if (!StringUtil.isSEmptyOrNull(cmaterialvid) && (body.getNnum() == null || body.getNassistnum() == null)) {
				errNumRows.add(body.getCrowno());
			}
			if (this.isVendorChosen(cmaterialvid, context) && StringUtil.isSEmptyOrNull(body.getCvendorid())) {
				errVendorRows.add(body.getCrowno());
			}
			// 泰开项目客开
			
			// 项目字段根据库存信息页签-可用量按辅助属性检查是否勾选进行判断
			String pk_org = bill.getHead().getPk_org();
			Boolean needCheckProd = checkProdect(cmaterialvid, pk_org);
			if (needCheckProd&&this.isProductorChosen(cmaterialvid, context) && StringUtil.isSEmptyOrNull(body.getCproductorid())) {
				errProductRows.add(body.getCrowno());
			}
			// 项目字段根据库存信息页签-可用量按辅助属性检查是否勾选进行判断
			Boolean needCheckProject = checkProject(cmaterialvid, pk_org);
			if (needCheckProject&&this.isProjectChosen(cmaterialvid, context) && StringUtil.isSEmptyOrNull(body.getCprojectid())) {
				errProjectRows.add(body.getCrowno());
			}
			if (this.isInvStateManage(cmaterialvid, context) && StringUtil.isSEmptyOrNull(body.getCstateid())) {
				errStateRows.add(body.getCrowno());
			}
			if (this.isCasscustChosen(cmaterialvid, context) && StringUtil.isSEmptyOrNull(body.getCasscustid())) {
				errCasscustRows.add(body.getCrowno());
			}
			if (this.isCffileidChosen(cmaterialvid, context) && StringUtil.isSEmptyOrNull(body.getCffileid())) {
				errCffileidRows.add(body.getCrowno());
			}

		}
		RuleUtils util = new RuleUtils();
		util.showErrByRows(errVendorRows, InvAdjustRes.getVendorNullErr());
		util.showErrByRows(errProductRows, InvAdjustRes.getProductorNullErr());
		util.showErrByRows(errProjectRows, InvAdjustRes.getProjectNullErr());
		util.showErrByRows(errStateRows, InvAdjustRes.getStateNullErr());
		util.showErrByRows(errNumRows, InvAdjustRes.getNumNullErr());
		util.showErrByRows(errCasscustRows, InvAdjustRes.getCasscustNullErr());
		util.showErrByRows(errCffileidRows, InvAdjustRes.getCffileidNullErr());

	}
	
	/**
	 * 根据物料查询物料库存信息页签-可用量按辅助属性检查是否勾选进行判断
	 * 
	 * @param cmaterialvid
	 * @param pk_org
	 * @return
	 */
	private Boolean checkProject(String cmaterialvid, String pk_org) {
		String whereSql = " pk_material='" + cmaterialvid + "' and pk_org='" + pk_org + "'  and nvl(dr,0)=0 ";
		List<MaterialStockVO> list = null;
		try {
			list = (List<MaterialStockVO>) new BaseDAO().retrieveByClause(MaterialStockVO.class, whereSql);
		} catch (DAOException e) {
			e.printStackTrace();
		}
		if (list != null && list.size() > 0) {
			return list.get(0).getFixasst2()==null?false:list.get(0).getFixasst2().booleanValue();
		}
		return true;
	}

	/**
	 * 根据物料查询物料库存信息页签-可用量按辅助属性检查是否勾选进行判断
	 * 
	 * @param cmaterialvid
	 * @param pk_org
	 * @return
	 */
	private Boolean checkProdect(String cmaterialvid, String pk_org) {
		String whereSql = " pk_material='" + cmaterialvid + "' and pk_org='" + pk_org + "'  and nvl(dr,0)=0 ";
		List<MaterialStockVO> list = null;
		try {
			list = (List<MaterialStockVO>) new BaseDAO().retrieveByClause(MaterialStockVO.class, whereSql);
		} catch (DAOException e) {
			e.printStackTrace();
		}
		if (list != null && list.size() > 0) {
			return list.get(0).getFixasst4() == null ? false : list.get(0).getFixasst4().booleanValue();
		}
		return true;
	}

	public List<Integer> checkRowType(TransformVO bill) throws BusinessException {
		TransformBodyVO[] bodyvos = bill.getBodys();
		int bodyLength = bodyvos.length;
		if (bodyLength <= 0) {
			return null;
		}
		if (bodyLength < 2) {
			throw new BusinessException(InvAdjustRes.getRowLengErr());
		}
		List<Integer> beforeIndex = new ArrayList<Integer>();
		for (int i = 0; i < bodyLength; i++) {
			if (null == bodyvos[i].getFbillrowflag()) {
				throw new BusinessException(InvAdjustRes.getRowTypeNullErr());
			}
			if (bodyvos[i].getFbillrowflag().equals(TransformRowFlag.BEFORECONVERT.value())
					&& VOStatus.DELETED != bodyvos[i].getStatus()) {
				beforeIndex.add(i);
			}
		}
		if (!bodyvos[0].getFbillrowflag().equals(TransformRowFlag.BEFORECONVERT.value())
				|| !bodyvos[bodyLength - 1].getFbillrowflag().equals(TransformRowFlag.AFTERCONVERT.value())) {
			throw new BusinessException(InvAdjustRes.getFirstAndLastRowTypeErr());
		}
		if (beforeIndex.size() > bodyLength / 2) {
			throw new BusinessException(InvAdjustRes.getTransformRowTypeErr());
		}
		for (int i = 0, j = i + 1; j < beforeIndex.size(); i++, j++) {
			int currentindex = beforeIndex.get(i);
			int nextindex = beforeIndex.get(j);
			if (nextindex == currentindex + 1) {
				throw new BusinessException(InvAdjustRes.getTransformRowTypeErr());
			}
		}
		return beforeIndex;

	}

	private List<TransformBodyVO> getBodysButDelete(TransformBodyVO[] bodyVOs) {
		List<TransformBodyVO> aftertempRows = new ArrayList<TransformBodyVO>();
		for (TransformBodyVO bodyVO : bodyVOs) {
			if (VOStatus.DELETED == bodyVO.getStatus()) {
				continue;
			}
			aftertempRows.add(bodyVO);
		}
		return aftertempRows;
	}

	/**
	 * 方法功能描述：
	 * <p>
	 * 检查转换前后的行内容是否存在转换前行等于转换后的行 <b>参数说明</b>
	 * 
	 * @param bill
	 * @throws BusinessException
	 *                           <p>
	 * @since 6.0
	 * @author chennn
	 * @time 2010-6-1 下午03:06:04
	 */
	public void checkTranformItem(TransformVO bill, List<Integer> beforeIndex) throws BusinessException {
		TransformBodyVO[] bodyVOs = bill.getBodys();
		Map<TransformBodyVO, List<String>> errInfo = new HashMap<TransformBodyVO, List<String>>();
		List<TransformBodyVO> aftertempRows = this.getBodysButDelete(bodyVOs);
		if (beforeIndex.size() == 1) {
			TransformBodyVO beforeRow = bodyVOs[beforeIndex.get(0)];
			List<TransformBodyVO> afterRows = aftertempRows.subList(1, aftertempRows.size());
			List<String> errRows = this.isBeforeSameWithAfter(beforeRow, afterRows);
			if (errRows.size() > 0) {
				errInfo.put(beforeRow, errRows);
				this.showItemSameErr(errInfo);
			}
		} else {
			List<TransformBodyVO> errBeforeRow = new ArrayList<TransformBodyVO>();
			for (int i = 0, j = i + 1; j < beforeIndex.size(); i++, j++) {
				int currentIndex = beforeIndex.get(i);
				int nextIndex = beforeIndex.get(j);
				TransformBodyVO beforeRow = bodyVOs[currentIndex];
				List<TransformBodyVO> afterRows = new ArrayList<TransformBodyVO>();
				for (int k = currentIndex + 1; k < nextIndex; k++) {
					// 过滤已删除表体行
					if (VOStatus.DELETED == bodyVOs[k].getStatus()) {
						continue;
					}
					afterRows.add(bodyVOs[k]);
				}
				List<String> errAfters = this.isBeforeSameWithAfter(beforeRow, afterRows);
				if (errAfters.size() > 0) {
					errBeforeRow.add(beforeRow);
					errInfo.put(beforeRow, errAfters);
				}
			}
			int lastBeforeIndex = beforeIndex.get(beforeIndex.size() - 1);
			TransformBodyVO beforeRow = bodyVOs[lastBeforeIndex];
//			List<TransformBodyVO> afterBodyRows = aftertempRows.subList(
//					lastBeforeIndex + 1, aftertempRows.size());

			// begin --调整最后一次校验表体行取值方式 lihui13 20180915
			List<TransformBodyVO> afterBodyRows = new ArrayList<TransformBodyVO>();
			int k = lastBeforeIndex + 1;
			while (k != bodyVOs.length) {
				if (k > bodyVOs.length) {
					break;
				}
				if (VOStatus.DELETED == bodyVOs[k].getStatus()) {
					k++;
					continue;
				}
				afterBodyRows.add(bodyVOs[k]);
				k++;
			}
			// end
			List<String> errAfters = this.isBeforeSameWithAfter(beforeRow, afterBodyRows);
			if (errAfters.size() > 0) {
				errBeforeRow.add(beforeRow);
				errInfo.put(beforeRow, errAfters);
			}
			this.showItemSameErr(errInfo);
		}
	}

	private String[] getKeys(TransformBodyVO beforeRow, String[] initFields) {

		List<String> keys = new ArrayList<String>();
		CollectionUtils.addArrayToList(keys, initFields);
		if (keys.contains(TransformBodyVO.VFREE_PREFIX)) {
			for (int i = 1; i <= TransformBodyVO.VREE_NUM; i++) {
				String vfree_i = TransformBodyVO.VFREE_PREFIX + i;
				keys.add(vfree_i);
			}
		}
		String cmaterialvid = beforeRow.getCmaterialvid();
		ICBSContext context = new ICBSContext();
		if (this.isVendorChosen(cmaterialvid, context)) {
			keys.add(TransformBodyVO.CVENDORID);
		}
		if (this.isProductorChosen(cmaterialvid, context)) {
			keys.add(TransformBodyVO.CPRODUCTORID);
		}
		if (this.isProjectChosen(cmaterialvid, context)) {
			keys.add(TransformBodyVO.CPROJECTID);
		}
		if (this.isInvStateManage(cmaterialvid, context)) {
			keys.add(TransformBodyVO.CSTATEID);
		}
		if (this.isCffileidChosen(cmaterialvid, context)) {
			keys.add(ICPubMetaNameConst.CFFILEID);
		}
		return keys.toArray(new String[keys.size()]);
	}

	private List<String> isBeforeSameWithAfter(TransformBodyVO beforeRow, List<TransformBodyVO> afterRows) {

		String[] fields = new String[] { TransformBodyVO.CMATERIALVID, TransformBodyVO.CASTUNITID,
				TransformBodyVO.VBATCHCODE, TransformBodyVO.VFREE_PREFIX, TransformBodyVO.CASSCUSTID };

		String[] keys = this.getKeys(beforeRow, fields);
		Object[] values = VOEntityUtil.getVOValues(beforeRow, keys);
		String key = StringUtil.mergeString(values, null, null);
		List<String> errRows = new ArrayList<String>();
		for (TransformBodyVO vo : afterRows) {
			Object[] afterValues = VOEntityUtil.getVOValues(vo, keys);
			String afterKey = StringUtil.mergeString(afterValues, null, null);
			if (StringUtil.isStringEqual(key, afterKey)) {
				errRows.add(vo.getCrowno());
			}
		}
		return errRows;

	}

	/**
	 * 方法功能描述：
	 * <p>
	 * 物料是否库存状态管理 <b>参数说明</b>
	 * 
	 * @param cmaterialvid
	 * @return
	 *         <p>
	 * @since 6.0
	 * @author chennn
	 * @time 2010-6-1 下午04:21:39
	 */
	private boolean isInvStateManage(String cmaterialvid, ICBSContext context) {
		UFBoolean fix1 = context.getInvInfo().getInvBasVO(cmaterialvid).getFix1();
		return fix1 == null ? false : fix1.booleanValue();

	}

	/**
	 * 方法功能描述：
	 * <p>
	 * 物料是否勾选项目辅助属性 <b>参数说明</b>
	 * 
	 * @param cmaterialvid
	 * @return
	 *         <p>
	 * @since 6.0
	 * @author chennn
	 * @time 2010-6-1 下午02:24:29
	 */
	private boolean isProjectChosen(String cmaterialvid, ICBSContext context) {
		UFBoolean fix2 = context.getInvInfo().getInvBasVO(cmaterialvid).getFix2();
		return fix2 == null ? false : fix2.booleanValue();
	}

	/**
	 * 方法功能描述：
	 * <p>
	 * 物料是否勾选特征码辅助属性 <b>参数说明</b>
	 * 
	 * @param cmaterialvid
	 * @return
	 *         <p>
	 * @since 6.36
	 * @author xuxq3
	 * @time 2015-04-06
	 */
	private boolean isCffileidChosen(String cmaterialvid, ICBSContext context) {
		UFBoolean fix100 = context.getInvInfo().getInvBasVO(cmaterialvid).getFix100();
		return fix100 == null ? false : fix100.booleanValue();
	}

	/**
	 * 是否勾选客户辅助属性
	 * 
	 * @param cmaterialvid
	 * @param context
	 * @return
	 */
	private boolean isCasscustChosen(String cmaterialvid, ICBSContext context) {
		UFBoolean fix5 = context.getInvInfo().getInvBasVO(cmaterialvid).getFix5();
		return fix5 == null ? false : fix5.booleanValue();
	}

	/**
	 * 方法功能描述：
	 * <p>
	 * 物料是否勾选供应商辅助属性 <b>参数说明</b>
	 * 
	 * @param cmaterialvid
	 * @return
	 *         <p>
	 * @since 6.0
	 * @author chennn
	 * @time 2010-6-1 上午10:46:09
	 */
	private boolean isVendorChosen(String cmaterialvid, ICBSContext context) {
		UFBoolean fix3 = context.getInvInfo().getInvBasVO(cmaterialvid).getFix3();
		return fix3 == null ? false : fix3.booleanValue();
	}

	/**
	 * 方法功能描述：
	 * <p>
	 * 物料是否勾选生产厂商辅助属性 <b>参数说明</b>
	 * 
	 * @param cmaterialvid
	 * @return
	 *         <p>
	 * @since 6.0
	 * @author chennn
	 * @time 2010-6-1 下午02:24:11
	 */
	private boolean isProductorChosen(String cmaterialvid, ICBSContext context) {
		UFBoolean fix4 = context.getInvInfo().getInvBasVO(cmaterialvid).getFix4();
		return fix4 == null ? false : fix4.booleanValue();
	}

	private void showItemSameErr(Map<TransformBodyVO, List<String>> errInfo) throws BusinessException {
		if (errInfo.size() <= 0) {
			return;
		}
		StringBuilder errMsg = new StringBuilder();
		errMsg.append(InvAdjustRes.getBeforeSameAfterErr()).append("\n");
		for (Map.Entry<TransformBodyVO, List<String>> err : errInfo.entrySet()) {
			String beforeRowNo = err.getKey().getCrowno();
			errMsg.append(InvAdjustRes.getBeforeRow() + beforeRowNo).append("  ");
			for (String afterRow : err.getValue()) {
				errMsg.append(InvAdjustRes.getAfterRow()).append(afterRow).append(",");
			}
		}

		throw new BusinessException(errMsg.toString());
	}

}
