package com.uas.report.util;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson.JSONObject;
import com.uas.report.SpecialProperties;
import com.uas.report.model.Master;

/**
 * 账套及其数据源管理
 * 
 * @author sunyj
 * @since 2016年11月4日 下午4:33:56
 */
public class MasterManager {

	/**
	 * 数据源
	 */
	private static Map<String, DruidDataSource> dataSources = new ConcurrentHashMap<>();

	/**
	 * 账套
	 */
	private static Set<Master> masters = new HashSet<>();

	private static Logger logger = LoggerFactory.getLogger(MasterManager.class);

	static {
		initAllDataSources();
	}

	/**
	 * 初始化所有数据源
	 */
	private static void initAllDataSources() {
		// 从配置中获取数据源信息
		SpecialProperties specialProperties = ContextUtils.getBean(SpecialProperties.class);
		JSONObject jsonObject = JSONObject.parseObject(specialProperties.getDataSourceInformation());
		Set<Entry<String, Object>> entrySet = jsonObject.entrySet();
		for (Entry<String, Object> entry : entrySet) {
			DruidDataSource dataSource = JSONObject.parseObject(entry.getValue().toString(), DruidDataSource.class);
			dataSources.put(entry.getKey().toUpperCase(), dataSource);
			masters.add(new Master(entry.getKey()));
		}
	}

	/**
	 * 获取账套对应的数据源
	 * 
	 * @param userName
	 *            账套名称
	 * @param profile
	 *            用于识别B2B、B2C账套的环境（dev、test、prod）
	 * @return 数据源
	 * @throws SQLException
	 */
	public static DataSource getDataSource(String userName, String profile) throws SQLException {
		if (StringUtils.isEmpty(userName)) {
			return null;
		}
		// 需要考虑B2B打印时账套名为B2B/10045740等类似的情况
		if (!StringUtils.isEmpty(profile)) {
			userName = userName.split("/")[0] + "_" + profile;
		}
		userName = userName.toUpperCase();
		DruidDataSource dataSource = dataSources.get(userName);
		// 如果Map里未存放该数据源，则可能是子帐套，需要从主账套表中获取
		if (dataSource == null) {
			Set<Entry<String, DruidDataSource>> entrySet = dataSources.entrySet();
			for (Entry<String, DruidDataSource> entry : entrySet) {
				dataSource = getDataSourceFromMainMaster(entry.getValue(), userName);
				if (dataSource != null) {
					dataSources.put(userName, dataSource);
					Master parent = new Master(entry.getKey());
					masters.add(new Master(userName, parent));
					return dataSource;
				}
			}
		}
		return dataSource;
	}

	/**
	 * 从主账套的MA_USER表中获取子账套数据源
	 * 
	 * @param mainMaster
	 * @param userName
	 * @return
	 * @throws SQLException 
	 */
	private static DruidDataSource getDataSourceFromMainMaster(DruidDataSource mainMaster, String userName) throws SQLException {
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		try {
			logger.info("mainMaster.getConnection..." + mainMaster.getUsername() + "," + userName);
			connection = mainMaster.getConnection();
			logger.info("mainMaster.getConnection done..." + mainMaster.getUsername() + "," + userName);
			// 先检查是否存在MASTER表
			String sql = "select count(*) from user_tables where table_name='MASTER'";
			preparedStatement = connection.prepareStatement(sql);
			resultSet = preparedStatement.executeQuery();
			resultSet.next();
			// 并不是每个数据源都有MA_USER表，如果不存在，紧接着遍历下一个数据源
			if (resultSet.getInt(1) == 0) {
				return null;
			}
			preparedStatement.close();
			resultSet.close();

			// 根据当前账套用户名获取其数据库配置信息
			sql = "select * from master where upper(MA_USER) = upper(?)";
			preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setString(1, userName);
			resultSet = preparedStatement.executeQuery();
			if (resultSet.next() && !StringUtils.isEmpty(resultSet.getString("MS_PWD"))) {
				String password = resultSet.getString("MS_PWD");
				// 除了用户名、密码，其他属性一样
				DruidDataSource result = mainMaster.cloneDruidDataSource();
				result.setUsername(userName);
				result.setPassword(password);
				return result;
			}
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.error("", e);
				}
			}
			if (preparedStatement != null) {
				try {
					preparedStatement.close();
				} catch (SQLException e) {
					logger.error("", e);
				}
			}
			if (connection != null) {
				try {
					connection.close();
				} catch (SQLException e) {
					logger.error("", e);
				}
			}
		}
		return null;
	}

	/**
	 * 根据账套名获取账套
	 * 
	 * @param userName
	 *            账套名称
	 * @return 账套
	 */
	public static Master getMaster(String userName) {
		if (StringUtils.isEmpty(userName)) {
			return null;
		}
		userName = userName.toUpperCase();
		for (Master master : masters) {
			if (master.getName().equals(userName)) {
				return master;
			}
		}
		return null;
	}
}
