/**
 * 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.platform.service.impl;

import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
import com.alibaba.druid.util.JdbcConstants;
import com.crunii.micro.platform.dto.EncryptJdbcKey;
import com.crunii.micro.platform.dto.EncryptKey;
import com.crunii.micro.platform.jdbc.EncryptColJdbcDao;
import com.crunii.micro.platform.service.EncryptColService;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author 田平 create 2019年7月5日下午4:36:08
 */
@Slf4j
public class EncryptColServiceImpl implements EncryptColService {

	@Autowired
	private EncryptColJdbcDao encryptColJdbcJdbcDao;

	private LoadingCache<EncryptJdbcKey, Boolean> encryptColumnJDBCCache = Caffeine.newBuilder()
			.expireAfterWrite(1, TimeUnit.DAYS)
			.refreshAfterWrite(60, TimeUnit.MINUTES)
			.build(key -> loadEncryptColumnJDBC(key));

	private LoadingCache<EncryptKey, Boolean> tableColumnCache = Caffeine.newBuilder()
			.expireAfterWrite(1, TimeUnit.DAYS)
			.refreshAfterWrite(60, TimeUnit.MINUTES)
			.build(key -> loadEncryptColsOfTab(key));

	/**
	 * 刷新所有加密字段缓存
	 */
	public void refreshEncryptColCache() {
		if (encryptColumnJDBCCache != null) {
			encryptColumnJDBCCache.invalidateAll();
		}
		if (tableColumnCache != null) {
			tableColumnCache.invalidateAll();
		}
	}

	public boolean checkEncryptColOfTab(String tabName, String colName) {
		EncryptKey encryptKey = new EncryptKey(tabName.toLowerCase(), colName.toLowerCase());
		return tableColumnCache.get(encryptKey);
	}

	private boolean loadEncryptColsOfTab(EncryptKey encryptKey) {
		log.info("load {} from database!", encryptKey);
		return encryptColJdbcJdbcDao.checkEncryptColOfTab(encryptKey);
	}

	public boolean checkEncryptColOfTabJDBC(String colName, String sql) {
		EncryptJdbcKey jdbcKey = new EncryptJdbcKey(colName.toLowerCase(), sql.toLowerCase());
		return encryptColumnJDBCCache.get(jdbcKey);
	}

	private boolean loadEncryptColumnJDBC(EncryptJdbcKey jdbcKey) {
		log.info("load {} from database!", jdbcKey);
		//配置表特殊处理
		if (jdbcKey.getSql().indexOf("t_encrypt_config") > -1) {
			return false;
		}
		List<SQLStatement> stmtList = SQLUtils.parseStatements(jdbcKey.getSql(), JdbcConstants.MYSQL);
		for (SQLStatement stmt : stmtList) {
			SchemaStatVisitor statVisitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.MYSQL);
			stmt.accept(statVisitor);
			for (SQLName tab : statVisitor.getOriginalTables()) {
				EncryptKey encryptKey = new EncryptKey(tab.getSimpleName().toLowerCase(), jdbcKey.getColName().toLowerCase());
				boolean succ = loadEncryptColsOfTab(encryptKey);
				if (succ) {
					return true;
				}
			}
		}
		return false;
	}

}
