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

import com.crunii.micro.common.utils.DateUtil;
import com.crunii.micro.domain.common.hibernate.action.*;
import com.crunii.micro.domain.dto.CallHolder;
import com.crunii.micro.domain.entitysql.main.TOperLogS;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.event.spi.*;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author 田平 create 2014-5-26下午4:30:50
 */
@Slf4j
public class OperLogListener implements PostUpdateEventListener, PostInsertEventListener, PostDeleteEventListener {

	private static final long serialVersionUID = 1L;

	public static String getValue(Object state) {
		String value = null;
		if (state != null) {
			if (state instanceof Date) {
				value = DateUtil.format((Date) state);
			} else {
				value = state.toString();
			}
		}
		return value;
	}

	public void onPostDelete(PostDeleteEvent event) {

		AbstractEntityPersister classMetadata = (AbstractEntityPersister) event.getPersister().getClassMetadata();
		String idName = event.getPersister().getIdentifierPropertyName();
		String idValue = event.getId().toString();
		String tableName = classMetadata.getTableName();
		log.debug("tableName:" + tableName + " idName:" + idName + ",idValue:" + idValue + " delete");
		Object[] propNames = event.getPersister().getPropertyNames();
		List<ActionDelete> deletes = new ArrayList<>(propNames.length);
		for (int i = 0; i < propNames.length; i++) {
			String columnValue = getValue(event.getDeletedState()[i]);
			ActionDelete delete = new ActionDelete();
			delete.setTableName(tableName);
			delete.setIdName(idName);
			delete.setIdValue(idValue);
			delete.setColumnName(propNames[i].toString());
			delete.setColumnValue(columnValue);
			deletes.add(delete);
		}
		doAction(deletes);
	}

	public void onPostInsert(PostInsertEvent event) {

		AbstractEntityPersister classMetadata = (AbstractEntityPersister) event.getPersister().getClassMetadata();
		String idName = event.getPersister().getIdentifierPropertyName();
		String idValue = event.getId().toString();
		String tableName = classMetadata.getTableName();
		log.debug("tableName:" + tableName + " idName:" + idName + ",idValue:" + idValue + " insert");
		Object[] propNames = event.getPersister().getPropertyNames();
		List<ActionInsert> inserts = new ArrayList<>(propNames.length);
		for (int i = 0; i < propNames.length; i++) {
			String columnValue = getValue(event.getState()[i]);
			ActionInsert insert = new ActionInsert();
			insert.setTableName(tableName);
			insert.setIdName(idName);
			insert.setIdValue(idValue);
			insert.setColumnName(propNames[i].toString());
			insert.setColumnValue(columnValue);
			inserts.add(insert);
		}
		doAction(inserts);

	}

	/**
	 * @see PostUpdateEventListener#onPostUpdate(PostUpdateEvent)
	 */
	public void onPostUpdate(PostUpdateEvent event) {

		AbstractEntityPersister classMetadata = (AbstractEntityPersister) event.getPersister().getClassMetadata();
		String idName = event.getPersister().getIdentifierPropertyName();
		String idValue = event.getId().toString();
		String tableName = classMetadata.getTableName();
		Object[] propNames = event.getPersister().getPropertyNames();
		log.debug("tableName:" + tableName + " idName:" + idName + ",idValue:" + idValue + " update");

		List<ActionUpdate> updates = new ArrayList<>(event.getDirtyProperties().length);
		for (int i = 0; i < event.getDirtyProperties().length; i++) {
			int index = event.getDirtyProperties()[i];
			String beforeValue = getValue(event.getOldState()[index]);
			String afterValue = getValue(event.getState()[index]);
			ActionUpdate update = new ActionUpdate();
			update.setTableName(tableName);
			update.setIdName(idName);
			update.setIdValue(idValue);
			update.setColumnName(propNames[index].toString());
			update.setBeforeValue(beforeValue);
			update.setAfterValue(afterValue);
			updates.add(update);
		}
		doAction(updates);
	}

	private void doAction(List<? extends Action> actions) {
		CallHolder holder = CallHolder.call.get();
		if (holder != null && StringUtils.hasText(holder.getCallUrl())) {
			if (holder.isNeedLog()) {
				List<TOperLogS> operLogs = new ArrayList<>();
				Date date = new Date();
				for (Action action : actions) {
					TOperLogS log = new TOperLogS();
					log.setCallSerial(holder.getCallSerial());
					log.setCallUrl(holder.getCallUrl());
					log.setCreateTime(date);
					if (holder.getWorker() != null) {
						log.setLoginId(holder.getWorker().getLoginId());
						log.setLoginCode(holder.getWorker().getLoginCode());
						log.setWorkerName(holder.getWorker().getWorkerName());
					}
					BeanUtils.copyProperties(action, log);
					operLogs.add(log);
				}
				//存储日志到线程变量
				OperLogHolder.storeOperLogs(operLogs);
			}
		}
	}

	@Override
	public boolean requiresPostCommitHanding(EntityPersister persister) {
		return true;
	}

}
