package com.wb.interact;

import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONArray;
import org.json.JSONObject;

import com.wb.util.WebUtil;

public class DBE {
	/**
	 * 获取数据库表树数据。
	 */
	public static void getTree(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String type = request.getParameter("type");
		String jndi = request.getParameter("jndi");
		String schema = request.getParameter("schema");
		String result;

		if ("db".equals(type)) {
			result = getSchemaList(jndi, null);
			//如果没有Schema直接返回表列表
			if (result == null)
				result = getTableList(jndi, null, null);
		} else if ("schema".equals(type))
			result = getTableList(jndi, schema, null);
		else
			result = getDbList();
		WebUtil.send(response, result);
	}

	/**
	 * 如果用户包含演示角色且非管理员，SQL语句仅允许执行select * from table，否则抛出异常。
	 */
	public static void checkSelectSql(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String sql = request.getParameter("sql");
		String roles[] = (String[]) WebUtil.fetchObject(request, "sys.roles");
		if (com.wb.util.StringUtil.indexOf(roles, "demo") != -1 && com.wb.util.StringUtil.indexOf(roles, "admin") == -1
				&& (!sql.startsWith("select * from ") || !com.wb.util.StringUtil.checkName(sql.substring(14), true)
						|| sql.substring(14).equalsIgnoreCase("WB_USER")))
			com.wb.util.SysUtil.accessDenied();
	}

	/**
	 * 从变量sys.jndi节点获得所有配置的jndi，并生成树组件脚本。
	 */
	public static String getDbList() throws Exception {
		JSONObject config = com.wb.util.JsonUtil.readObject(new File(com.wb.common.Base.path, "wb/system/var.json"));
		HashMap<String, Object> map = new HashMap<String, Object>();
		ArrayList<Entry<String, Object>> sortedItems;
		config = config.optJSONObject("sys").optJSONObject("jndi");
		Set<Entry<String, Object>> es = config.entrySet();
		String key;
		JSONObject jo;
		JSONArray ja = new JSONArray();

		// 默认jndi，插入到首行
		config.remove("default");
		for (Entry<String, Object> e : es) {
			key = e.getKey();
			map.put(key, ((JSONArray) e.getValue()).optString(0));
		}
		sortedItems = com.wb.util.SortUtil.sortKey(map);
		jo = new JSONObject();
		jo.put("text", "default");
		jo.put("jndi", "default");
		jo.put("type", "db");
		jo.put("iconCls", "db_icon");
		ja.put(jo);

		for (Entry<String, Object> e : sortedItems) {
			jo = new JSONObject();
			jo.put("text", e.getKey());
			jo.put("jndi", e.getKey());
			jo.put("type", "db");
			jo.put("iconCls", "db_icon");
			ja.put(jo);
		}
		return ja.toString();
	}

	/**
	 * 获取指定jndi所有数据库表JSON脚本。
	 * @param jndi jndi名称。
	 * @param schema 表Schema。
	 * @param tables 已经配置的表定义。
	 * @return 表列表JSON脚本。 
	 */
	public static String getTableList(String jndi, String schema, HashSet<String> tables) throws Exception {
		Connection conn = null;
		ResultSet rs = null;
		boolean isFirst = true, hasTableDefine = tables != null;
		String types[] = { "TABLE" }, tableSchema, tableName, tableText, upperTableName,
				jndiText = com.wb.util.StringUtil.quote(jndi);
		StringBuilder buf = new StringBuilder();
		ArrayList<Entry<String, String>> sortedEntries;
		HashMap<String, String> tableMap = new HashMap<String, String>();

		try {
			conn = com.wb.util.DbUtil.getConnection(jndi);
			rs = conn.getMetaData().getTables(null, schema, null, types);
			while (rs.next()) {
				tableSchema = com.wb.util.StringUtil.opt(rs.getString(2));
				tableName = rs.getString(3);
				tableMap.put(tableName, tableSchema);
			}
			sortedEntries = com.wb.util.SortUtil.sortKey(tableMap);
			buf.append('[');
			for (Entry<String, String> entry : sortedEntries) {
				if (isFirst)
					isFirst = false;
				else
					buf.append(',');
				tableName = entry.getKey();
				tableText = com.wb.util.StringUtil.quote(tableName);
				tableSchema = com.wb.util.StringUtil.quote(entry.getValue());
				buf.append("{\"text\":");
				buf.append(tableText);
				buf.append(",\"type\":\"table\",\"table\":");
				buf.append(tableText);
				buf.append(",\"schema\":");
				buf.append(tableSchema);
				buf.append(",\"jndi\":");
				buf.append(jndiText);
				buf.append(",\"leaf\":true,\"iconCls\":\"");
				upperTableName = tableName.toUpperCase();
				if (hasTableDefine && tables.contains(upperTableName)) {
					tables.remove(upperTableName);
					buf.append("table_add_icon\"}");
				} else {
					buf.append("table_icon\"}");
				}
			}
			// 不匹配的表添加到最后
			if (hasTableDefine && schema == null) {
				for (String fullName : tables) {
					fullName = com.wb.util.StringUtil.quote(fullName);
					buf.append(",{\"text\":");
					buf.append(fullName);
					buf.append(",\"type\":\"table\",\"table\":");
					buf.append(fullName);
					buf.append(",\"schema\":\"\",\"jndi\":");
					buf.append(jndiText);
					buf.append(",\"leaf\":true,\"iconCls\":\"table_delete_icon\"}");
				}
			}
			buf.append(']');
			return buf.toString();
		} finally {
			com.wb.util.DbUtil.close(rs);
			com.wb.util.DbUtil.close(conn);
		}
	}

	/**
	 * 获取指定jndi所有Schema列表。
	 * @param jndi jndi名称。
	 * @param tables 已经配置的表定义。
	 * @return Schema列表JSON脚本。 如果没有Schema返回null。
	 */
	public static String getSchemaList(String jndi, HashSet<String> tables) throws Exception {
		Connection conn = null;
		ResultSet rs = null;
		String types[] = { "TABLE" }, schema, tableName, upperTableName, jndiText = com.wb.util.StringUtil.quote(jndi);
		StringBuilder buf = new StringBuilder();
		HashMap<String, Boolean> schemaMap = new HashMap<String, Boolean>();
		ArrayList<Entry<String, Boolean>> entryList;
		boolean isFirst = true, hasTableDefine = tables != null;

		try {
			conn = com.wb.util.DbUtil.getConnection(jndi);
			rs = conn.getMetaData().getTables(null, null, null, types);
			while (rs.next()) {
				schema = com.wb.util.StringUtil.opt(rs.getString(2));
				tableName = rs.getString(3);
				upperTableName = tableName.toUpperCase();
				schemaMap.put(schema, true);
				if (hasTableDefine && tables.contains(upperTableName))
					tables.remove(upperTableName);
			}
			//如果不包含Schema返回null
			if (schemaMap.isEmpty() || schemaMap.size() == 1 && schemaMap.containsKey(""))
				return null;
			entryList = com.wb.util.SortUtil.sortKey(schemaMap);
			buf.append('[');
			for (Entry<String, Boolean> entry : entryList) {
				schema = com.wb.util.StringUtil.quote(entry.getKey());
				if (isFirst)
					isFirst = false;
				else
					buf.append(',');
				buf.append("{\"text\":");
				buf.append(schema);
				buf.append(",\"jndi\":");
				buf.append(jndiText);
				buf.append(",\"schema\":");
				buf.append(schema);
				buf.append(",\"type\":\"schema\",\"iconCls\":\"db_form_icon\"}");
			}
			// 不匹配的表添加到最后
			if (hasTableDefine) {
				for (String fullName : tables) {
					fullName = com.wb.util.StringUtil.quote(fullName);
					buf.append(",{\"text\":");
					buf.append(fullName);
					buf.append(",\"type\":\"table\",\"table\":");
					buf.append(fullName);
					buf.append(",\"schema\":\"\",\"jndi\":");
					buf.append(jndiText);
					buf.append(",\"leaf\":true,\"iconCls\":\"table_delete_icon\"}");
				}
			}
			buf.append(']');
			return buf.toString();
		} finally {
			com.wb.util.DbUtil.close(rs);
			com.wb.util.DbUtil.close(conn);
		}
	}

	/**
	 * 从指定表下载二进制字段内容。
	 */
	public static void downloadBlob(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String jndi = request.getParameter("__jndi"), tableName = request.getParameter("__tableName"),
				fieldName = request.getParameter("__fieldName");
		String selectSql = com.wb.util.DbUtil.buildSQLs(jndi, tableName, false, 1, null, new JSONObject().put(fieldName, 1), null,
				null)[3];
		ResultSet rs = (ResultSet) com.wb.util.DbUtil.run(request, selectSql, jndi);
		com.wb.util.DbUtil.outputBlob(rs, request, response, "download");
	}

	/**
	 * 上传文件数据至指定数据库表二进制字段。
	 */
	public static void uploadBlob(HttpServletRequest request, HttpServletResponse response) throws Exception {
		setBlob(request, false);
	}

	/**
	 * 上传文件数据至指定数据库表二进制字段。
	 */
	public static void clearBlob(HttpServletRequest request, HttpServletResponse response) throws Exception {
		setBlob(request, true);
	}

	/**
	 * 上传文件数据至指定数据库表二进制字段或清除该字段。
	 * @param isClear 是否清除二进制字段，true清除，false更新。
	 */
	private static void setBlob(HttpServletRequest request, boolean isClear) throws Exception {
		String jndi = WebUtil.fetch(request, "__jndi"), tableName = WebUtil.fetch(request, "__tableName"),
				fieldName = WebUtil.fetch(request, "__fieldName");

		if (isClear)
			request.setAttribute(fieldName, "");
		else
			request.setAttribute(fieldName, request.getAttribute("file"));
		String updateSql = com.wb.util.DbUtil.buildSQLs(jndi, tableName, false, 1, null, new JSONObject().put(fieldName, 1), null,
				null)[1];
		com.wb.util.DbUtil.run(request, updateSql, jndi);
	}
}
