/**
 * 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.hibernate.action.listener;

import com.crunii.micro.common.utils.AESUtil;
import com.crunii.micro.domain.entity.main.TsmEncryptTest;
import com.crunii.micro.platform.service.EncryptColService;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.event.spi.*;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.ReflectionUtils;

import java.lang.reflect.Field;

/**
 * @author 田平 create 2019年7月5日下午2:52:27
 */
@Slf4j
public class EncryptColListener implements PreInsertEventListener, PreUpdateEventListener, PostLoadEventListener {

	private static final long serialVersionUID = 1L;

	@Autowired
	private EncryptColService encryptColumnService;

	private void encrypt(AbstractEntityPersister classMetadata, Object[] state, String[] propNames, String tabName) {
		for (int i = 0; i < propNames.length; i++) {
			String colName = classMetadata.getPropertyColumnNames(propNames[i])[0];
			if (encryptColumnService.checkEncryptColOfTab(tabName, colName)) {
				Object curr = state[i];
				if (curr != null) {
					state[i] = AESUtil.encrypt(curr.toString());
				}
			}
		}
	}

	@Override
	public boolean onPreInsert(PreInsertEvent event) {
		AbstractEntityPersister classMetadata = (AbstractEntityPersister) event.getPersister().getClassMetadata();
		String tabName = classMetadata.getTableName().toLowerCase();
		String[] propNames = event.getPersister().getPropertyNames();
		encrypt(classMetadata, event.getState(), propNames, tabName);
		return false;
	}

	@Override
	public boolean onPreUpdate(PreUpdateEvent event) {
		AbstractEntityPersister classMetadata = (AbstractEntityPersister) event.getPersister().getClassMetadata();
		String tabName = classMetadata.getTableName().toLowerCase();
		String[] propNames = event.getPersister().getPropertyNames();
		encrypt(classMetadata, event.getState(), propNames, tabName);
		return false;
	}

	/**
	 * @see PostLoadEventListener#onPostLoad(PostLoadEvent)
	 */
	@Override
	public void onPostLoad(PostLoadEvent event) {
		AbstractEntityPersister classMetadata = (AbstractEntityPersister) event.getPersister().getClassMetadata();
		String tabName = classMetadata.getTableName().toLowerCase();
		String[] propNames = event.getPersister().getPropertyNames();
		Field field = null;
		String propName = null;
		String colname = null;
		for (int i = 0; i < propNames.length; i++) {
			propName = propNames[i];
			colname = classMetadata.getPropertyColumnNames(propName)[0].toLowerCase();
			if (encryptColumnService.checkEncryptColOfTab(tabName, colname)) {
				field = ReflectionUtils.findRequiredField(event.getEntity().getClass(), propName);
				if (field != null) {
					try {
						field.setAccessible(true);
						Object value = field.get(event.getEntity());
						if (value != null) {
							ReflectionUtils.setField(field, event.getEntity(), AESUtil.decrypt(value.toString()));
						}
					} catch (Exception e) {
						log.info("{}.{} decrypt error!", tabName, colname);
					}
				}
			}
		}
	}

	public static void main(String[] args) throws Exception {
		TsmEncryptTest encrypt = new TsmEncryptTest();
		encrypt.setEncryptName("abcd1231");
		Field field = ReflectionUtils.findRequiredField(TsmEncryptTest.class, "encryptName");
		field.setAccessible(true);
		System.out.println(field.get(encrypt));
	}

}
