package com.leanwo.activiti.listener.base;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.delegate.TaskListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.leanwo.activiti.exception.WorkflowException;
import com.leanwo.activiti.service.base.impl.UserPreference;
import com.leanwo.activiti.util.SpringUtil;
import com.leanwo.activiti.util.StringUtil;

/**
 * 多实例任务（开发人员定义）创建监听器
 * <ul>
 * <li>执行SQL语句，获取审批人的集合</li>
 * <li>设置审批人</li>
 * </ul>
 * .
 *
 * @author YangZhiJie
 */
public class MultiInstanceUserTaskByUserProgramTaskAssignmentListener implements TaskListener {

	/**  */
	private static Logger logger = LoggerFactory.getLogger(MultiInstanceUserTaskByUserProgramTaskAssignmentListener.class);

	/** 任务责任人变量名称. */
	private Expression assignListVariableName;

	/** 节点名称. */
	private Expression nodeName;

	/** Sql语句. */
	private Expression sqlDataExpression;

	/**
	 * 
	 *
	 * @param execution
	 */
	@Override
	public void notify(DelegateTask delegateTask) {
		String assignListName = assignListVariableName.getExpressionText();
		String node = nodeName.getExpressionText();
		String sqlData = sqlDataExpression.getExpressionText();

		if (StringUtil.isEmpty(assignListName)) {
			throw new WorkflowException(String.format("开发人员自定义审批人(%s)未定义变量assignListVariableName。", node));
		}

		if (StringUtil.isEmpty(sqlData)) {
			throw new WorkflowException(String.format("开发人员自定义审批人(%s)未定义变量sqlDataExpression。", node));
		}

		List<Long> userIds = null;
		try {
			userIds = queryApproveUser(delegateTask, sqlData);
		} catch (SQLException e) {
			logger.error(String.format("开发人员自定义审批人(%s)SQL语句定义错误。", node), e);
			throw new WorkflowException(String.format("开发人员自定义审批人(%s)SQL语句定义错误。%s。", node, e.getMessage()));
		}

		if (userIds == null || userIds.size() == 0) {
			throw new WorkflowException(String.format("开发人员自定义审批人(%s)查询不到审批人，请检查设置。", node));
		}

		// 提前设置好审批人
		List<String> userIdStrings = new ArrayList<String>();
		userIds.forEach(userId -> {
			userIdStrings.add(userId.toString());
		});

		delegateTask.setVariable(assignListName, userIdStrings);
	}

	/**
	 * 查询审批人.
	 *
	 * @param execution
	 * @return 审批人集合
	 * @throws SQLException
	 */
	private List<Long> queryApproveUser(DelegateTask delegateTask, String sqlData) throws SQLException {
		// 从流程变量获取记录id
		Long recordId = (Long) delegateTask.getVariable(UserPreference.RECORD_ID);
		Long accountId = (Long) delegateTask.getVariable(UserPreference.ACCOUNT_ID);
		Long createUserId = (Long) delegateTask.getVariable(UserPreference.CREATE_USER_ID);

		String sqlCommand = sqlData.replace(":recordId", recordId.toString()).replace(":createUserId", createUserId.toString());
		Connection connection = null;
		PreparedStatement preparedStatement = null;

		List<Long> userIds = new ArrayList<Long>();
		try {
			DataSource dataSource = SpringUtil.getBean("dataSource" + accountId);
			connection = dataSource.getConnection();
			preparedStatement = connection.prepareStatement(sqlCommand);

			// 执行查询操作，并输出数据
			ResultSet rs = preparedStatement.executeQuery();
			while (rs.next()) {
				long userId = rs.getLong(1);
				userIds.add(userId);
			}
			preparedStatement.execute();
		} finally {
			try {
				if (preparedStatement != null) {
					preparedStatement.close();
				}
				if (connection != null) {
					connection.close();
				}
			} catch (SQLException e) {
				logger.error("数据库连接关闭失败");
				e.printStackTrace();
			}
		}
		return userIds;
	}

	/**
	 * Gets the 任务接受人(String).
	 *
	 * @return the 任务接受人(String)
	 */
	public Expression getAssignListVariableName() {
		return assignListVariableName;
	}

	/**
	 * Sets the 任务接受人(String).
	 *
	 * @param assignListVariableName the new 任务接受人(String)
	 */
	public void setAssignListVariableName(Expression assignListVariableName) {
		this.assignListVariableName = assignListVariableName;
	}

	/**
	 * Gets the 节点名称.
	 *
	 * @return the 节点名称
	 */
	public Expression getNodeName() {
		return nodeName;
	}

	/**
	 * Sets the 节点名称.
	 *
	 * @param nodeName the new 节点名称
	 */
	public void setNodeName(Expression nodeName) {
		this.nodeName = nodeName;
	}

	/**
	 * Gets the sql语句.
	 *
	 * @return the sql语句
	 */
	public Expression getSqlDataExpression() {
		return sqlDataExpression;
	}

	/**
	 * Sets the sql语句.
	 *
	 * @param sqlDataExpression the new sql语句
	 */
	public void setSqlDataExpression(Expression sqlDataExpression) {
		this.sqlDataExpression = sqlDataExpression;
	}
}
