package p2.pao;

import p2.p2server.P2Server;
import p2.util.DataBindBody;
import p2.util.P2AppException;
import p2.util.P2Exception;
import p2.util.P2Format;
import p2.util.logging.P2Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;

/**
 * 用于动态物件数据绑定的操作类
 * 
 */
public class PaoFieldObjectBind extends PaoFieldDataBind {
	String errorGroup;
	String errorKey;
	String foreignlinkWhere;
	/**
	 * 强制包含？
	 */
	boolean enforceContain;
	/**
	 * 选择是自动创建目标记录?
	 */
	boolean createDestRecord;
	/**
	 * 可多选?
	 */
	boolean multiSelect;
	/**
	 * 源物件
	 */
	private String objectName;
	/**
	 * where条件
	 */
	String listWhere;
	/**
	 * where条件列表
	 */
	ArrayList conditionalListWhere;
	/**
	 * 关于源栏位和目标栏位（当前栏位）映射的缓存
	 */
	HashMap<String,String[][]> cachedKeyMapHash;
	/**
	 * 用于查找的多个key的where条件
	 */
	String multiKeyWhereForLookup;
	/**
	 * 是否所有栏位允许设置空值。
	 */
	boolean allAttrsNullable;
    /**
     * 不允许设置为空值的栏位数组。
     */
    String[] notAllowNullAttrs;
	public static final String ISNULL = "0";
	public static final String ISNOTNULL = "1";

	public PaoFieldObjectBind(PaoField mbv) {
		super(mbv);
		errorGroup = "system";
		errorKey = "notvalid";
		foreignlinkWhere = null;
		enforceContain = false;
		createDestRecord = false;
		multiSelect = false;

		setObjectName(null);
		listWhere = null;
		conditionalListWhere = new ArrayList(10);
		cachedKeyMapHash = new HashMap(16);
		multiKeyWhereForLookup = null;
		allAttrsNullable = false;
		notAllowNullAttrs = null;

		sourceFieldVector = new Vector();
		destFieldVector = new Vector();
		nullAllowedVector = new Vector();
		isOrder = new Vector();
		isDesc = new Vector();
		isDataBind = new Vector();
		bindIfDestExist = new Vector();
		bindIfDestNull = new Vector();

		// dataBindBodys = new ArrayList<DataBindBody>();
		dataBindBodyMap = new HashMap<String, DataBindBody>(16);
		overwrittenKeyMap = false;
	}

	@Override
	public void chooseActualListValues() throws P2Exception {
		if (this.databindid == null) {
			return;
		}
		String str1 = getSite();
		c localc;
		if ((localc = getPaoField().getPaoFieldInfo().getDataBindInfo()) == null) {
			localc = getPaoField().getPao().getPaoServer().getP2DBInfoCache().getDataBindInfo(this.databindid);
			getPaoField().getPaoFieldInfo().setDataBindInfo(localc);
		}
		if (localc == null) {
			throw new P2AppException("system", "dataBindNotExist", new String[] { this.databindid });
		}
		setForeignLink(((q) localc).c(str1), ((q) localc).d(str1));
		setListCriteria(((q) localc).d(str1));
		Object localObject;
		setEnforceContain(((r) ((q) localc).a(str1)).c);
		localObject = (r) localc.a(str1);
		setSourceFields(((r) localObject).d);
		setDestinationFields(((r) localObject).e);
		setIsOrder(((r) localObject).g);
		setIsDesc(((r) localObject).h);
		setIsDatabind(((r) localObject).i);
		setNullAllowed(((r) localObject).f);
		setBindIfDestExist(((r) localObject).j);
		setBindIfDestNull(((r) localObject).k);
		setDataBindBodys();
		if (!this.overwrittenKeyMap) {
			setKeyMap(((q) localc).c(str1),
					(String[]) this.destFieldVector.toArray(new String[0]),
					(String[]) this.sourceFieldVector.toArray(new String[0]));
		}
	}

	/**
	 * Get foreignlink PAO set.
	 * 
	 * @param where
	 * @return
	 * @throws P2Exception
	 * 
	 */
	public PaoSetRemote getPaoSet(String where) throws P2Exception {
		return getPaoSet(where, "");
	}

	/**
	 * Get foreignlink PAO set by identifier
	 * 
	 * @param where
	 * @param identifier
	 * @return
	 * @throws P2Exception
	 * 
	 */
	public PaoSetRemote getPaoSet(String where, String identifier) throws P2Exception {
		if (identifier == null) {
            identifier = "";
        }
		if (getPaoField().getPao().isZombie()) {
            return paoField.getPao().getPaoSet("__" + getObjectName() + paoField.getName() + identifier,
                    getObjectName(), (new SqlFormat(getPaoField().getPao(), where)).format());
        } else {
            return paoField.getPao().getPaoSet("__" + getObjectName() + paoField.getName() + identifier,
                    getObjectName(), where);
        }
	}

	/**
	 * Get foreignlink PAO set.
	 * 
	 * @return
	 * @throws P2Exception
	 * 
	 */
	public PaoSetRemote getPaoSet() throws P2Exception {
		return getPaoSet(combineWheres());
	}

	@Override
	public boolean hasList() {
		return true;
	}

	/**
	 * 设置选择列表关联
	 * 
	 * @param objectName
	 * @param whereClause
	 *            ;验证where
	 */
	public void setForeignLink(String objectName, String whereClause) {
		this.setObjectName(objectName);
		foreignlinkWhere = whereClause;
	}

	/**
	 * 设置选择列表的过滤条件
	 * 
	 * @param listWhere
	 */
	public void setListCriteria(String listWhere) {
		this.listWhere = listWhere;
	}

	/**
	 * 设置错误信息
	 * 
	 * @param eg
	 * @param ek
	 */
	public void setErrorMessage(String eg, String ek) {
		if (eg != null) {
			errorGroup = eg;
			if (ek != null) {
                errorKey = ek;
            }
		}
	}

	/**
	 * 组合where
	 * 
	 * @return
	 */
	String combineWheres() {
		StringBuffer result = new StringBuffer();
		if (foreignlinkWhere != null && foreignlinkWhere.length() > 0) {
            result.append("(").append(foreignlinkWhere).append(" ) ");
        }
		if (listWhere != null && listWhere.length() > 0) {
			if (result.length() > 0) {
                result.append("AND ");
            }
			result.append("(").append(listWhere).append(" )");
		}
		return result.toString();
	}

	/**
	 * 获取where
	 * 
	 * @return
	 */
	public String getListCriteria() {
		return listWhere;
	}

	@Override
	public void setValueFromLookup(PaoRemote sourcePao) throws P2Exception {
		Pao pao = getPaoField().getPao();
		String targetAttrName = getPaoField().getFieldName();
        String[][] cachedKeyMap = getCachedKeyMapFromHash(sourcePao.getName());
		if (cachedKeyMap == null) {
            cachedKeyMap = getMatchingAttrs(sourcePao.getName());
        }
		for (int i = 0; i < cachedKeyMap.length; i++) {
			if (null != dataBindBodyMap && dataBindBodyMap.get(cachedKeyMap[i][1]) != null) {
				// 栏位没有勾选数据绑定的时候跳出。
				if (!dataBindBodyMap.get(cachedKeyMap[i][1]).isDataBind()) {
                    continue;
                }
				// 目标栏位不存在，（目标栏位存在时绑定数据?）,（目标栏位不存在，则不绑定数据）
				if (!dataBindBodyMap.get(cachedKeyMap[i][1]).isDestFieldExist()
						&& dataBindBodyMap.get(cachedKeyMap[i][1]).isBindIfDestExist()) {
                    continue;
                }
			}

			if (cachedKeyMap[i][0].equalsIgnoreCase(targetAttrName)
					|| !pao.getString(cachedKeyMap[i][0]).equals(sourcePao.getString(cachedKeyMap[i][1]))) {
				// if(((String)
				// bindifDestExist[i]).equals(P2Format.getStoreYesValue()))
				// {

				// 源栏位为空值时，如果“允许复制空值”=0,跳出
				if (sourcePao.isNull(cachedKeyMap[i][1]) && null != dataBindBodyMap
						&& dataBindBodyMap.get(cachedKeyMap[i][1]) != null
						&& !dataBindBodyMap.get(cachedKeyMap[i][1]).isNullAllowed()) {
                    continue;
                }
				// 目标栏位不为空值时，如果“目标栏位为空时复制数据”=1，跳出
				if (!pao.isNull(cachedKeyMap[i][0]) && null != dataBindBodyMap
						&& dataBindBodyMap.get(cachedKeyMap[i][1]) != null
						&& dataBindBodyMap.get(cachedKeyMap[i][1]).isBindIfDestNull()) {
                    continue;
                }
				pao.setValue(cachedKeyMap[i][0], sourcePao.getString(cachedKeyMap[i][1]), SAMEVALUEVALIDATION);
				// }
			}
		}
	}

	@Override
	public String getMatchingAttr() throws P2Exception {
		return getMatchingAttr(getObjectName());
	}

	@Override
	public String getMatchingAttr(String sourceObjectName) throws P2Exception {
        String[][] cachedKeyMap = getMatchingAttrs(sourceObjectName);
		int i;
		for (i = cachedKeyMap.length - 1; i >= 0 && !getPaoField().getName().equalsIgnoreCase(cachedKeyMap[i][0]); i--) {
        }
		return cachedKeyMap[i][1];
	}

	/**
	 * 以源物件作为key来获取栏位匹配映射数组。
	 * 
	 * @param sourceName
	 *            源物件
	 * @return
	 * @throws P2Exception
	 */
	protected String[][] getMatchingAttrs(String sourceName) throws P2Exception {
		Pao pao = getPaoField().getPao();
		String targetAttrName = getPaoField().getName();
        String[][] cachedKeyMap = getCachedKeyMapFromHash(sourceName.toUpperCase());
		if (cachedKeyMap != null) {
            return cachedKeyMap;
        }
        Object[] keyMap = pao.getMatchingAttrs(sourceName.toUpperCase(), getPaoField().getName());
		if (keyMap == null) {
            throw new P2AppException("system", "LookupNeedRegister", new String[] { sourceName, targetAttrName });
        }
		cachedKeyMap = new String[keyMap.length][2];
		int k = 0;
        String[] tmp = new String[keyMap.length];
		for (int i = 0; i < keyMap.length; i++) {
			cachedKeyMap[i][0] = (String) ((Object[]) keyMap[i])[0];
			cachedKeyMap[i][1] = (String) ((Object[]) keyMap[i])[1];
			if (!((Boolean) ((Object[]) keyMap[i])[2]).booleanValue()
					&& !cachedKeyMap[i][0].equalsIgnoreCase(targetAttrName)) {
				tmp[k] = cachedKeyMap[i][0];
				k++;
			}
		}

		for (int index = 0; index < k; index++) {
			if (notAllowNullAttrs == null) {
                notAllowNullAttrs = new String[k];
            }
			notAllowNullAttrs[index] = tmp[index];
		}

		if (notAllowNullAttrs == null) {
            allAttrsNullable = true;
        }
		return cachedKeyMap;
	}

	/**
	 * 将源关键栏位和目标关键栏位放入映射缓存中，并使用已设置源物件作为key来缓存。
	 * 
	 * @param targetKeys
	 * @param sourceKeys
	 */
	public void setLookupKeyMapInOrder(String[] targetKeys, String[] sourceKeys) {
		if (targetKeys == null || sourceKeys == null || sourceKeys.length == 0
				|| sourceKeys.length != targetKeys.length) {
			return;
		}
        String[][] cachedKeyMap = new String[targetKeys.length][2];
		for (int i = 0; i < targetKeys.length; i++) {
			cachedKeyMap[i][0] = targetKeys[i];
			cachedKeyMap[i][1] = sourceKeys[i];
		}

		cachedKeyMapHash.put(getObjectName() != null ? ( (getObjectName().toUpperCase())) : "", cachedKeyMap);
	}

	/**
	 * 将源关键栏位和目标关键栏位放入映射缓存中，并使用源物件作为key来缓存。
	 * 
	 * @param sourcePaoName
	 * @param targetKeys
	 * @param sourceKeys
	 */
	public void setKeyMap(String sourcePaoName, String[] targetKeys, String[] sourceKeys) {
        String[][] cachedKeyMap = new String[targetKeys.length][2];
		for (int i = 0; i < targetKeys.length; i++) {
			cachedKeyMap[i][0] = targetKeys[i];
			cachedKeyMap[i][1] = sourceKeys[i];
		}

		cachedKeyMapHash.put(sourcePaoName.toUpperCase(), cachedKeyMap);

		overwrittenKeyMap = true;
	}

	/**
	 * 将源关键栏位和目标关键栏位的映射放入映射缓存中，并使用已设置源物件作为key来缓存。
	 * 
	 * @param map
	 */
	public void setLookupKeyMapInOrder(String[][] map) {
		cachedKeyMapHash.put(getObjectName() != null ? ((getObjectName().toUpperCase())) : "", map);
	}

	/**
	 * 所有目标栏位允许复制空值
	 */
	public final void setAllAttrsNullable() {
		allAttrsNullable = true;
	}

	/**
	 * 不允许复制空值的栏位
	 * 
	 * @param attrs
	 */
	public final void setNotAllowNullAttrs(String[] attrs) {
		notAllowNullAttrs = attrs;
	}

	/**
	 * 设置用于查找的多个key的where条件
	 * 
	 * @param w
	 */
	public void setMultiKeyWhereForLookup(String w) {
		multiKeyWhereForLookup = w;
	}

	/**
	 * 将源物件名称作为key来获取源栏位和目标栏位（当前栏位）的映射
	 * 
	 * @param sourcePaoName
	 * @return
	 */
	private String[][] getCachedKeyMapFromHash(String sourcePaoName) {
        String[][] map = cachedKeyMapHash
                .get(sourcePaoName != null ? sourcePaoName.toUpperCase() : "");
		if (map == null && cachedKeyMapHash.size() == 1) {
            map = cachedKeyMapHash.get("");
        }
		if (map != null && map.length == 0) {
            map = null;
        }
		return map;
	}

	@Override
	public PaoSetRemote smartFill(String value, boolean exact) throws P2Exception {
		PaoSetRemote retSet = smartFind(value, exact);
		if (retSet == null) {
            return retSet;
        }
		if (retSet.getPao(0) != null && retSet.getPao(1) == null) {
            setValueFromLookup(retSet.getPao(0));
        }
		return retSet;
	}

	public PaoSetRemote smartFillWithoutReset(String value, boolean exact) throws P2Exception {
        String[][] cachedKeyMap = getCachedKeyMapFromHash(getObjectName());
		if (cachedKeyMap == null && getObjectName() != null) {
            cachedKeyMap = getMatchingAttrs(getObjectName());
        }
		PaoSetRemote retSet = getList();
		if (!retSet.getPaoSetInfo().isPersistent()) {
            return null;
        }
		int i;
		for (i = cachedKeyMap.length - 1; i >= 0 && !cachedKeyMap[i][0].equalsIgnoreCase(getPaoField().getName()); i--) {
        }
		Pao thisPao = getPaoField().getPao();
		PaoSetRemote emptySet = thisPao.getPaoServer().getPaoSet(getObjectName(), thisPao.getUserInfo());
		emptySet.setWhere("1=2");
		emptySet.setFlag(8L, true);
		PaoRemote each = null;
		int count = 0;
		PaoRemote lastFound = null;
		for (int j = 0; (each = retSet.getPao(j)) != null; j++) {
			if (exact) {
				if (each.getString(cachedKeyMap[i][0]).equalsIgnoreCase(value)) {
					lastFound = each;
					each.copyWithNoSpecific(emptySet);
					count++;
				}
				continue;
			}
			if (each.getString(cachedKeyMap[i][0]).toUpperCase().indexOf(value.toUpperCase()) != -1) {
				lastFound = each;
				each.copyWithNoSpecific(emptySet);
				count++;
			}
		}

		if (count == 1) {
            setValueFromLookup(thisPao);
        }
		return emptySet;
	}

	@Override
	public PaoSetRemote smartFind(String value, boolean exact) throws P2Exception {
        String[][] cachedKeyMap = getCachedKeyMapFromHash(getObjectName());
		if (cachedKeyMap == null && getObjectName() != null) {
            cachedKeyMap = getMatchingAttrs(getObjectName());
        }
		PaoSetRemote listSet = getList();
		String where = listSet.getCompleteWhere();
		PaoSetRemote retSet = getPaoField().getPao().getPaoServer().getPaoSet(getObjectName(),
				getPaoField().getPao().getUserInfo());
		retSet.setOBJECTDataBindLookup(true);
		retSet.setOwner(listSet.getOwner());
		retSet.setApp(listSet.getApp());
		retSet.setWhere(where);
		retSet.setFlag(8L, true);
		if (!retSet.getPaoSetInfo().isPersistent()) {
            return null;
        }
		int i;
		for (i = cachedKeyMap.length - 1; i >= 0 && !cachedKeyMap[i][0].equalsIgnoreCase(getPaoField().getName()); i--) {
        }
		if (exact) {
			retSet.setQbeExactMatch(true);
			retSet.setQbe(cachedKeyMap[i][1], value);
		} else {
			retSet.setQbeExactMatch(false);
			retSet.setQbeCaseSensitive(false);
			String searchType = getPaoField().getPaoFieldInfo().getSearchType();
			int p2type = getPaoField().getType();
			if (p2type == 8 || p2type == 9 || p2type == 6 || p2type == 7 || p2type == 11) {
                retSet.setQbe(cachedKeyMap[i][1], value);
            } else {
                retSet.setQbe(cachedKeyMap[i][1], value + "%");
            }
		}
		return retSet;
	}

	public PaoSetRemote smartFindWithoutReset(String value, boolean exact) throws P2Exception {
        String[][] cachedKeyMap = getCachedKeyMapFromHash(getObjectName());
		if (cachedKeyMap == null && getObjectName() != null) {
            cachedKeyMap = getMatchingAttrs(getObjectName());
        }
		PaoSetRemote retSet = getList();
		if (!retSet.getPaoSetInfo().isPersistent()) {
            return null;
        }
		int i;
		for (i = cachedKeyMap.length - 1; i >= 0 && !cachedKeyMap[i][0].equalsIgnoreCase(getPaoField().getName()); i--) {
        }
		Pao thisPao = getPaoField().getPao();
		PaoSetRemote emptySet = thisPao.getPaoServer().getPaoSet(getObjectName(), thisPao.getUserInfo());
		emptySet.setWhere("1=2");
		emptySet.setFlag(8L, true);
		PaoRemote each = null;
		int count = 0;
		PaoRemote lastFound = null;
		for (int j = 0; (each = retSet.getPao(j)) != null; j++) {
			if (exact) {
				if (each.getString(cachedKeyMap[i][0]).equalsIgnoreCase(value)) {
					lastFound = each;
					each.copyWithNoSpecific(emptySet);
					count++;
				}
				continue;
			}
			if (each.getString(cachedKeyMap[i][0]).toUpperCase().startsWith(value.toUpperCase())) {
				lastFound = each;
				each.copyWithNoSpecific(emptySet);
				count++;
			}
		}

		return emptySet;
	}

	@Override
	public PaoSetRemote smartFind(String sourceObj, String value, boolean exact) throws P2Exception {
        String[][] cachedKeyMap = getCachedKeyMapFromHash(sourceObj);
		if (cachedKeyMap != null && sourceObj != null) {
            return getPaoField().getPao().smartFindByObjectName(sourceObj, getPaoField().getName(), value, exact,
                    cachedKeyMap);
        }
		if (cachedKeyMap == null) {
            return getPaoField().getPao().smartFindByObjectNameDirect(sourceObj, getPaoField().getName(), value, exact);
        } else {
            return null;
        }
	}

	/**
	 * 
	 * @param field
	 * @param condition
	 *            ,0为空值时，附加此where;1不为空值时，附加此where
	 * @param where
	 */
	public void addConditionalListWhere(String field, String condition, String where) {
		conditionalListWhere.add(new String[] { field, condition, where });
	}

	/**
	 * 清除condition list where
	 */
	public void clearConditionalListWhere() {
		conditionalListWhere.clear();
	}

	/**
	 * 
	 * @param conditionalWhereList
	 * @return
	 * @throws P2Exception
	 */
	public String evalConditionalWhere(ArrayList conditionalWhereList) throws P2Exception {
		if (conditionalWhereList == null || conditionalWhereList.isEmpty()) {
            return null;
        }
		StringBuffer sb = new StringBuffer();
		if (!conditionalListWhere.isEmpty()) {
			Iterator it = conditionalListWhere.iterator();
			boolean first = true;
			do {
				if (!it.hasNext()) {
                    break;
                }
				if (!first) {
                    sb.append(" and ");
                } else {
                    first = false;
                }
                String[] cw = (String[]) it.next();
				if ("0".equals(cw[1])) {
					if (getPaoField(cw[0]).isNull()) {
						sb.append("(");
						sb.append(cw[2]);
						sb.append(")");
					}
				} else if ("1".equals(cw[1]) && !getPaoField(cw[0]).isNull()) {
					sb.append("(");
					sb.append(cw[2]);
					sb.append(")");
				}
			} while (true);
		}
		return sb.toString();
	}

	/**
	 * 设置物件名称
	 * 
	 * @param objectName
	 */
	public void setObjectName(String objectName) {
		this.objectName = objectName;
	}

	/**
	 * 获取物件名称
	 * 
	 * @return
	 */
	public String getObjectName() {
		return objectName;
	}

	/**
	 * 是否强制验证数据
	 * 
	 * @return
	 */
	public boolean isEnforceContain() {
		return enforceContain;
	}

	/**
	 * 设置是否强制包含
	 * 
	 * @param enforceContain
	 */
	public void setEnforceContain(boolean enforceContain) {
		this.enforceContain = enforceContain;
	}

	/**
	 * 是否在选取时创建目标记录
	 * 
	 * @return
	 */
	public boolean isCreateDestRecord() {
		return createDestRecord;
	}

	/**
	 * 设置是否在选取时创建目标记录
	 * 
	 * @param createDestRecord
	 */
	public void setCreateDestRecord(boolean createDestRecord) {
		this.createDestRecord = createDestRecord;
	}

	/**
	 * 是否可以多选
	 * 
	 * @return
	 */
	public boolean isMultiSelect() {
		return multiSelect;
	}

	/**
	 * 设置源栏位
	 * 
	 * @param fl
	 */
	private void setSourceFields(Vector fl) {
		sourceFieldVector = fl;
	}

	/**
	 * 设置目标栏位
	 * 
	 * @param fl
	 */
	private void setDestinationFields(Vector fl) {
		destFieldVector = fl;
	}

	/**
	 * 设置目标栏位是否允许复制空值
	 * 
	 * @param fl
	 */
	private void setNullAllowed(Vector fl) {
		nullAllowedVector = fl;
	}

	/**
	 * 设置是否可以多选
	 * 
	 * @param multiSelect
	 */
	private void setMultiSelect(boolean multiSelect) {
		this.multiSelect = multiSelect;
	}

	/**
	 * 设置是否支持排序
	 * 
	 * @param isOrder
	 */
	private void setIsOrder(Vector isOrder) {
		this.isOrder = isOrder;
	}

	/**
	 * 设置排序是否倒序
	 * 
	 * @param isDesc
	 */
	private void setIsDesc(Vector isDesc) {
		this.isDesc = isDesc;
	}

	/**
	 * 设置是否实时复制(绑定)源栏位数据到目标栏位
	 * 
	 * @param isDatabind
	 */
	private void setIsDatabind(Vector isDatabind) {
		this.isDataBind = isDatabind;
	}

	/**
	 * 设置是否目标栏位存在时绑定数据
	 * 
	 * @param bindIfDestExist
	 */
	private void setBindIfDestExist(Vector bindIfDestExist) {
		this.bindIfDestExist = bindIfDestExist;
	}

	/**
	 * 设置是否目标栏位为空值可以绑定数据
	 * 
	 * @param bindIfDestNull
	 */
	private void setBindIfDestNull(Vector bindIfDestNull) {
		this.bindIfDestNull = bindIfDestNull;
	}

	/**
	 * 检查并设置动态数据绑定里的数据库定义里存在的源栏位和目标栏位
	 * 
	 * @return 目标栏位存在 return true;目标栏位全部不存在 return false;
	 * @throws P2Exception
	 */
	/*
	 * private boolean setDestAndSourceFieldsExist() throws P2Exception { String
	 * dests = ""; String sources = ""; String bindifdestexit = ""; String
	 * bindifdestnull = ""; String bindifsourcenull = ""; PaoSetRemote existSet =
	 * P2Server.getP2Server().getPaoSet("PS_OBJECTCOLS",
	 * P2Server.getP2Server().getSystemUserInfo()); existSet.setQbe("objectname",
	 * paoField.getPao().getName()); for (int i = 0, count = destFieldVector.size();
	 * i < count; i++) { if (destFieldVector.elementAt(i) == null) continue; if
	 * (((String)isDataBind.elementAt(i)).equals(P2Format.getStoreNoValue()))
	 * continue; existSet.setQbe("fieldname", (String)
	 * destFieldVector.elementAt(i)); existSet.reset(); if (existSet.getPao(0) !=
	 * null && !existSet.getPao(0).toBeDeleted()) //
	 * 如果数据库定义里目标物件存在目标栏位，且不是删除状态，则保存该栏位到destFieldExist，并保存对应的源栏位到sourceFieldExist {
	 * dests += (String) destFieldVector.elementAt(i) + " "; sources += (String)
	 * sourceFieldVector.elementAt(i) + " "; bindifdestexit += (String)
	 * bindIfDestExist.elementAt(i) + " "; bindifdestnull += (String)
	 * bindIfDestNull.elementAt(i) + " "; bindifsourcenull += (String)
	 * nullAllowedVector.elementAt(i) + " "; } } if (dests.length() >= 1 &&
	 * sources.length() >= 1) { destFieldExist = dests.trim().split(" ");
	 * sourceFieldExist = sources.trim().split(" "); bindifDestExist =
	 * bindifdestexit.split(" "); bindifDestNull = bindifdestnull.split(" ");
	 * bindifSourceNull = bindifsourcenull.split(" "); return true; } return
	 * false;// 所有目标栏位都不存在返回false }
	 */

	/**
	 * 通过目标栏位获取源栏位
	 * 
	 * @param destField
	 * @return
	 */
	private String getSourceField(String destField) {
		for (int i = 0, numX = destFieldVector.size(); i < numX; i++) {
			if (destField.equalsIgnoreCase(
					destFieldVector.elementAt(i) == null ? null : destFieldVector.elementAt(i).toString())) {
                return (String) sourceFieldVector.elementAt(i);
            }
		}
		return null;
	}

	@Override
	public PaoSetRemote getList() throws P2Exception {
		resetListValues();
        String[][] cachedKeyMap = getCachedKeyMapFromHash(getObjectName());
		if (listWhere == null && multiKeyWhereForLookup == null && cachedKeyMap == null && getObjectName() != null
				&& P2Server.getP2Server().getP2DBInfoCache().getPaoSetInfo(getObjectName()).getKeyField().length > 1) {
            cachedKeyMap = getMatchingAttrs(getObjectName());
        }
		String w = null;
		if (listWhere != null && listWhere.trim().length() > 0) {
            w = listWhere;
        }
		String cw = evalConditionalWhere(conditionalListWhere);
		if (cw != null && !"".equals(cw.trim())) {
            if (w == null) {
                w = cw;
            } else {
                w = "(" + w + ") and (" + cw + ")";
            }
        }
		if (w == null && multiKeyWhereForLookup != null) {
            w = multiKeyWhereForLookup;
        }
		if (w == null) {
            w = "";
        }
		PaoSetRemote ms = getPaoSet(w, "list");
		ms.setOBJECTDataBindLookup(true);// 设置where
		/*
		 * if (listWhere == null && multiKeyWhereForLookup == null && cachedKeyMap !=
		 * null && cachedKeyMap.length > 1) { String thisAttr = getPaoField().getName();
		 * multiKeyWhereForLookup = null; for (int i = 0; i < cachedKeyMap.length; i++)
		 * if (!cachedKeyMap[i][0].equalsIgnoreCase(thisAttr))
		 * ms.setQbe(cachedKeyMap[i][1],
		 * getPaoField().getPao().getString(cachedKeyMap[i][0])); else
		 * ms.setQbe(cachedKeyMap[i][1], ""); }
		 */
		StringBuilder order_by = new StringBuilder();// 排序
		for (int i = 0; i < isOrder.size(); i++) {
			if (isOrder.elementAt(i) == null) {
                continue;
            }
			if (isOrder.elementAt(i).equals(P2Format.getStoreYesValue())) {
				if (sourceFieldVector.size() <= i) {
					break;
				}
				if (order_by.length() > 0) {
                    order_by.append(" , ");
                }

				order_by.append(sourceFieldVector.elementAt(i).toString()).append(" ").append(isDesc.elementAt(i).equals(P2Format.getStoreYesValue()) ? "desc" : "");
			}
		}
		if (order_by.length() > 0) {
			ms.setOrderBy(order_by.toString());
			ms.reset();
		}
		return ms;
	}

	/**
	 * 验证查找的值是否可以作为目标栏位（当前栏位）的值。 验证强制包含
	 */
	@Override
	public void validate() throws P2Exception {
		if (getPaoField().isNull())// 如果没有一个目标栏位（当前栏位），则不作验证。
        {
            return;
        }
        String[][] cachedKeyMap = getCachedKeyMapFromHash(getObjectName());
		if (cachedKeyMap == null && notAllowNullAttrs == null && allAttrsNullable && getObjectName() != null
				&& P2Server.getP2Server().getP2DBInfoCache().getPaoSetInfo(getObjectName()).getKeyField().length > 0) {
            try {
                cachedKeyMap = getMatchingAttrs(getObjectName());
            } catch (P2Exception e) {
                P2Logger l = getPaoField().getPao().getPaoLogger();
                if (l.isWarnEnabled()) {
                    l.warn(e);
                }
            }
        }
		if (!allAttrsNullable && notAllowNullAttrs != null) {
			for (int i = 0; i < notAllowNullAttrs.length; i++) {
				String attr = notAllowNullAttrs[i];
				if (getPaoField(attr).isNull()) {
                    Object[] params = {getPaoField(attr).getColumnTitle(), getPaoField().getColumnTitle()};
					throw new P2AppException("system", "nullBeforeSet", params);
				}
			}

		}

		/*
		 * String sourceField; if (isEnforceContain() && (sourceField =
		 * getSourceField(getPaoField().getName())) != null) {// 强制验证 resetListValues();
		 * PaoSetRemote msi = getPaoSet(); msi.setOBJECTDataBindLookup(true);
		 * msi.setQbe(sourceField, getPaoField().getString()); msi.reset(); if (msi ==
		 * null || msi.isEmpty()) { if (msi != null) msi.close(); Object params[] = {
		 * paoField.getColumnTitle(), paoField.getCurrentValue().toString() }; throw new
		 * P2AppException(errorGroup, errorKey, params); } else { msi.close(); return; }
		 * }
		 */

		if (isEnforceContain()) {// 强制验证
			resetListValues();
			PaoSetRemote msi = getPaoSet();
			msi.setOBJECTDataBindLookup(true);
			String sourceField;
			if ((sourceField = getSourceField(getPaoField().getName())) != null) {
                msi.setQbe(sourceField, getPaoField().getString());
            } else if (cachedKeyMap != null && cachedKeyMap.length != 0) {
				for (int k = 0; k < cachedKeyMap.length; k++) {
					if (getPaoField().getName().equalsIgnoreCase(cachedKeyMap[k][0]) && cachedKeyMap[k][1] != null) {
						msi.setQbe(cachedKeyMap[k][1], getPaoField().getString());
						break;
					}
				}
			}
			msi.reset();
			if (msi == null || msi.isEmpty()) {
				if (msi != null) {
                    msi.close();
                }
                Object[] params = {paoField.getColumnTitle(), paoField.getCurrentValue().toString()};
				throw new P2AppException(errorGroup, errorKey, params);
			} else {
				msi.close();
			}
		}
	}

	/**
	 * 执行Action方法
	 */
	@Override
	public void action() throws P2Exception {
		if (sourceFieldVector.isEmpty() || getPaoField().isNull()) {
            return;
        }
		PaoRemote ownerPao = paoField.getPao();

		PaoSetRemote msSourceSet = getPaoSet();
		PaoRemote msSourcePao = null;
		boolean moreThanOne = false;
		if (msSourceSet != null) {
			msSourcePao = msSourceSet.getPao(0);
			if (msSourceSet.getPao(1) != null) {
				PaoSetRemote smartFound = smartFind(getPaoField().getString(), true);
				msSourcePao = smartFound.getPao(0);
				if (smartFound.getPao(1) != null) {
                    moreThanOne = true;
                }
			}
		}
		if (msSourceSet == null || msSourcePao == null) {
            return;
        }
		if (moreThanOne) {
            throw new P2AppException("system", "wrongValidationWhere", new String[] { getPaoField().getName() });
        }
		// 系统动态数据绑定有栏位列表记录的时候绑定栏位数据
		for (int k = 0; k < sourceFieldVector.size(); k++) {
			if (sourceFieldVector.elementAt(k) == null) {
                continue;
            }
			String sourceField = (String) sourceFieldVector.elementAt(k);// 源栏位名称
			String destField = (String) destFieldVector.elementAt(k);// 目标栏位名称
			// 如果勾选了实时“绑定数据”到目标栏位，继续执行，否则跳出当前循环
			/*
			 * if (((String) isDataBind.elementAt(k)).equals(P2Format.getStoreNoValue()))
			 * continue;
			 */// if not databind，exec continue
			// 查找验证目标栏位是否存在
			PaoSetRemote destField_col = P2Server.getP2Server().getPaoSet("PS_OBJECTCOLS",
					P2Server.getP2Server().getSystemUserInfo());
			SqlFormat sql = new SqlFormat("objectname=:1 and fieldname=:2");
			sql.setObject(1, "PS_OBJECTCOLS", "objectname", ownerPao.getName());
			sql.setObject(2, "PS_OBJECTCOLS", "fieldname", destField);
			destField_col.setWhere(sql.format());
			destField_col.reset();
			if (destField_col.getPao(0) == null
					|| (destField_col.getPao(0) != null && destField_col.getPao(0).toBeDeleted())) {
				if (bindIfDestExist.elementAt(k).equals(P2Format.getStoreYesValue())) {
                    continue;
                } else {
                    throw new P2AppException("system", "destFieldNotExist", new String[] { destField.toUpperCase() });
                }
			}

			// 源栏位为空时，允许复制空值到源栏位，则执行。目标栏位为空值时绑定数据。当为true时，只有目标栏位为空值时，才会将源栏位的值绑定到目标栏位
			String sourceValue = msSourcePao.getString(sourceField);
			if (sourceValue == null || "".equals(sourceValue.trim())) {
				if (((String) nullAllowedVector.elementAt(k)).equalsIgnoreCase(P2Format.getStoreNoValue())) {
                    continue;// If selected "Allow copy null", and source value
                }
								// is null, exec continue.
			}
			if (bindIfDestNull.elementAt(k).equals(P2Format.getStoreYesValue())
					&& !ownerPao.isNull(destField)) {
				continue;// If selected "Data bind if dest field null", and dest
							// value is not null, exec continue.
			}
			ownerPao.setValue(destField, sourceValue, 2L);// PII-1187
		}

	}

	/**
	 * 将源栏位、目标栏位等Vector信息封装到DataBindBody对象里
	 * 
	 * @return
	 */
	private void setDataBindBodys() throws P2Exception {
		DataBindBody db = null;
		/*
		 * PaoSetRemote existSet = P2Server.getP2Server().getPaoSet("PS_OBJECTCOLS",
		 * P2Server.getP2Server().getSystemUserInfo());
		 * existSet.setWhere("objectname = '" + paoField.getPao().getName() + "'");
		 * existSet.reset(); Vector<String> existFields = new Vector<String>();
		 * PaoRemote field; for (int j = 0, len = existSet.count(); j < len; j++) {
		 * field = existSet.getPao(j); if (!field.toBeDeleted()) {
		 * existFields.add(field.getString("fieldname")); } }
		 */
		for (int i = 0; i < sourceFieldVector.size(); i++) {
			if (null == dataBindBodyMap) {
                dataBindBodyMap = new HashMap<String, DataBindBody>();
            }
			if (null == sourceFieldVector.elementAt(i)) {
                continue;
            }
			db = new DataBindBody();
			db.setSourceField((String) sourceFieldVector.elementAt(i));
			db.setDataBind(isDataBind.elementAt(i).equals(P2Format.getStoreYesValue()));
			db.setDestField((String) destFieldVector.elementAt(i));
			db.setOrder(isOrder.elementAt(i).equals(P2Format.getStoreYesValue()));
			db.setDesc(isDesc.elementAt(i).equals(P2Format.getStoreYesValue()));
			db.setNullAllowed(nullAllowedVector.elementAt(i).equals(P2Format.getStoreYesValue()));
			db.setBindIfDestExist(bindIfDestExist.elementAt(i).equals(P2Format.getStoreYesValue()));
			db.setBindIfDestNull(bindIfDestNull.elementAt(i).equals(P2Format.getStoreYesValue()));
			db.setDestFieldExist(false);

			if (!isDataBind.elementAt(i).equals(P2Format.getStoreNoValue())
					&& destFieldVector.elementAt(i) != null) {
				// if (existFields.contains((String) destFieldVector.elementAt(i))) {
				db.setDestFieldExist(getPaoField().getPao().getPaoFieldInfoStatic((String) destFieldVector.elementAt(i)) != null);
			}

			dataBindBodyMap.put((String) sourceFieldVector.elementAt(i), db);
		}
	}

	/**
	 * 源栏位
	 */
	Vector sourceFieldVector;
	/**
	 * 目标栏位
	 */
	Vector destFieldVector;
	/**
	 * 允许复制空值
	 */
	Vector nullAllowedVector;
	/**
	 * 是否排序
	 */
	Vector isOrder;
	/**
	 * 如果排序，是否倒序
	 */
	Vector isDesc;
	/**
	 * 是否绑定数据到目标栏位
	 */
	Vector isDataBind;
	/**
	 * 目标栏位存在时绑定数据 。如果目标栏位不存在则报错。当为true时，如果目标栏位不存在则不绑定数据。
	 */
	Vector bindIfDestExist;
	/**
	 * 目标栏位为空值时绑定数据。当为true时，只有目标栏位为空值时，才会将源栏位的值绑定到目标栏位。
	 */
	Vector bindIfDestNull;
	/**
	 * 是否重写了keyMap
	 */
	private boolean overwrittenKeyMap;
	/**
	 * 目标栏位集合中存在的集合
	 */
	// private String destFieldExist[];
	/**
	 * 源栏位集合中对应的目标栏位存在的集合
	 */
	// private String sourceFieldExist[];
	/**
	 * 目标栏位集合中存在栏位对应的“目标栏位存在时绑定数据”的值
	 */
	// private String bindifDestExist[];
	/**
	 * 目标栏位集合中存在栏位对应的“目标栏位为空值时绑定数据”的值
	 */
	// private String bindifDestNull[];;
	/**
	 * 目标栏位集合中存在栏位对应的“允许复制空值”的值
	 */
	// private String bindifSourceNull[];

	// private List<DataBindBody> dataBindBodys;
	private HashMap<String, DataBindBody> dataBindBodyMap;

	/**
	 * 已废弃，建议使用setDataBindId(String dataBindId)
	 * 
	 * @param databindid
	 */
	@Deprecated
	public void setValueListId(String databindid) {
		setDataBindId(databindid);
	}

	/**
	 * 已废弃，建议使用getDataBindId()
	 *
	 */
	@Deprecated
	public String getValueListId() {
		return getDataBindId();
	}
}
