/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved.
 * <a>http://www.crunii.com</a>
 */
package com.crunii.micro.domain.common.jdbc.dto;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.ToString;

import javax.persistence.Transient;
import java.io.Serializable;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * 通过jdbc获取的domain对象，必须使用
 * BaseJdbcTemplate.queryForBean BaseJdbcTemplate.queryForBeans
 * BaseNPJdbcTemplate.queryForBean BaseNPJdbcTemplate.queryForBeans
 * 特别是对于复杂sql单独写的，一般通DomainUtil，的静态方法指定forUpdate
 * 所有的BeanUtils.copy 必须排除DEFAULT_EXCLUSIONS_PROPS，这两个属性
 *
 * @author 田平 create 2020/11/27 15:40
 */
@ToString
public abstract class AbsSetProps implements Serializable {

	/**
	 * BeanUtil.copyProperties注意排除---------特别注意-----------
	 */
	@JsonIgnore
	@Transient
	private transient Map<String, Object> domainSetProps;

	/**
	 * BeanUtil.copyProperties注意排除---------特别注意-----------
	 * 如果没有通过DomainUtil的方法获取对象，又需要更新该对象的时候，
	 * 必须在sql获取后设置domainForUpdate=false，保证更新的属性在保存的时候能写到domainSetProps中
	 */
	@JsonIgnore
	@Transient
	private transient boolean domainForUpdate = false;

	private static final Set<String> DEFAULT_EXCLUSIONS = new HashSet<>();

	public static final String[] ignoreProperties;

	static {
		//设置默认过滤的属性，特别是在对bean进行copy的时候，必须使用这个
		DEFAULT_EXCLUSIONS.add("domainSetProps");
		DEFAULT_EXCLUSIONS.add("domainForUpdate");
		//---------------BeanUtil.copy 排除数组--
		ignoreProperties = DEFAULT_EXCLUSIONS.stream().toArray(String[]::new);
	}

	public AbsSetProps() {

	}

	public AbsSetProps(boolean domainForUpdate) {
		this.domainForUpdate = domainForUpdate;
		if (this.domainForUpdate) {
			domainSetProps = new LinkedHashMap<>();
		}
	}

	public Map<String, Object> getDomainSetProps() {
		return domainSetProps;
	}

	public void setDomainSetProps(Map<String, Object> domainSetProps) {
		this.domainSetProps = domainSetProps;
	}

	public boolean isDomainForUpdate() {
		return domainForUpdate;
	}

	public void setDomainForUpdate(boolean domainForUpdate) {
		this.domainForUpdate = domainForUpdate;
		if (this.domainForUpdate) {
			if (domainSetProps == null) {
				domainSetProps = new LinkedHashMap<>();
			} else {
				domainSetProps.clear();
			}
		} else {
			this.domainSetProps = null;
		}
	}

	protected void fireSet(String propName, Object newValue) {
		if (domainForUpdate) {
			//取消反射获取属性名，domain通过模板代码自动生成，提高效率，超大量反射会有性能损失
//			String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
//			String propName = DomainUtil.getPropName(methodName);
			domainSetProps.put(propName, newValue);
		}
	}

	/**
	 * 更新执行完成后清空修改属性map
	 */
	public void resetDomainSetProps() {
		if (domainSetProps != null) {
			domainSetProps.clear();
		}
	}

}
