package org.inria.bmajwatcher.server.data;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.inria.biomaj.session.bank.BiomajSQLQuerier;
import org.inria.biomaj.sql.SQLConnection;
import org.inria.biomaj.sql.SQLConnectionFactory;
import org.inria.bmajwatcher.server.UserManagerServiceImpl;


/**
 * Returns the X last errors and warnings.
 *  
 * @author rsabas
 *
 */
public class ErrorRetriever {
	
	
	private static Logger log = Logger.getLogger(ErrorRetriever.class);
	
	/**
	 * Returns the latest x error/warning messages as an xml
	 * string following the smargwt RestDataSource syntax.
	 * 
	 * @param messageMax maximum number of messages to retrieve
	 * @param userKey key identifying user whose bank errors are retrieved
	 * @return
	 */
	public static String getMessages(String messageMax, String userKey) {
		int messageCount;
		try {
			messageCount = Integer.valueOf(messageMax);
		} catch (NumberFormatException ex) {
			messageCount = 20;
		}
		
		boolean admin = UserManagerServiceImpl.isAdminKey(userKey);
		
		int id = 1;
		StringBuilder xmlOutput = new StringBuilder();
		SQLConnection connection = SQLConnectionFactory.getConnection();
		
		String query = "";
		
		if (!admin) {
			int userId = 1;
			query = "SELECT iduser FROM bw_user WHERE auth_key='" + userKey + "'";
			Statement stat = connection.getStatement();
			ResultSet rs = connection.executeQuery(query, stat);
			try {
				if (rs.next()) {
					userId = rs.getInt(1);
				} else {
					log.error("Unknown key : " + userKey);
					SQLConnectionFactory.closeConnection(stat);
					return "";
				}
			} catch (SQLException e) {
				e.printStackTrace();
				SQLConnectionFactory.closeConnection(stat);
				return "";
			}
			SQLConnectionFactory.closeConnection(stat);
			
			// Query for non admin...
			query = "SELECT * FROM message WHERE idmessage IN " +
					"(SELECT ref_idmessage FROM session_has_message WHERE ref_idsession IN (SELECT idsession FROM session WHERE ref_idupdateBank IN (SELECT idupdateBank FROM updateBank WHERE ref_idconfiguration IN (SELECT idconfiguration FROM configuration WHERE ref_idbank IN (SELECT idbank FROM bank WHERE ref_iduser IN (SELECT ref_iduser FROM bw_user_has_group WHERE ref_idgroup IN (SELECT ref_idgroup FROM bw_user_has_group WHERE ref_iduser=" + userId + "))))))) " +
					"OR idmessage IN (SELECT ref_idmessage FROM sessionTask_has_message WHERE ref_idsessionTask IN (SELECT ref_idsessionTask FROM session_has_sessionTask WHERE ref_idsession IN (SELECT idsession FROM session WHERE ref_idupdateBank IN (SELECT idupdateBank FROM updateBank WHERE ref_idconfiguration IN (SELECT idconfiguration FROM configuration WHERE ref_idbank IN (SELECT idbank FROM bank WHERE ref_iduser IN (SELECT ref_iduser FROM bw_user_has_group WHERE ref_idgroup IN (SELECT ref_idgroup FROM bw_user_has_group WHERE ref_iduser=" + userId + ")))))))) " +
					"OR idmessage IN (SELECT ref_idmessage FROM metaprocess_has_message WHERE ref_idmetaprocess IN (SELECT idmetaprocess FROM metaprocess WHERE ref_idsessionTask IN (SELECT ref_idsessionTask FROM session_has_sessionTask WHERE ref_idsession IN (SELECT idsession FROM session WHERE ref_idupdateBank IN (SELECT idupdateBank FROM updateBank WHERE ref_idconfiguration IN (SELECT idconfiguration FROM configuration WHERE ref_idbank IN (SELECT idbank FROM bank WHERE ref_iduser IN (SELECT ref_iduser FROM bw_user_has_group WHERE ref_idgroup IN (SELECT ref_idgroup FROM bw_user_has_group WHERE ref_iduser=" + userId + "))))))))) " +
					"OR idmessage IN (SELECT ref_idmessage FROM process_has_message WHERE ref_idprocess IN (SELECT idprocess FROM process WHERE ref_idmetaprocess IN (SELECT idmetaprocess FROM metaprocess WHERE ref_idsessionTask IN (SELECT ref_idsessionTask FROM session_has_sessionTask WHERE ref_idsession IN (SELECT idsession FROM session WHERE ref_idupdateBank IN (SELECT idupdateBank FROM updateBank WHERE ref_idconfiguration IN (SELECT idconfiguration FROM configuration WHERE ref_idbank IN (SELECT idbank FROM bank WHERE ref_iduser IN (SELECT ref_iduser FROM bw_user_has_group WHERE ref_idgroup IN (SELECT ref_idgroup FROM bw_user_has_group WHERE ref_iduser=" + userId + ")))))))))) " +
					"ORDER BY idmessage DESC LIMIT " + messageCount;
		} else {
			query = "SELECT * FROM message ORDER BY idmessage DESC LIMIT " + messageCount;
		}
		
		
		int actualMessages = 0; // In case of orphan messages
		
		
		SQLConnection mainCnt = SQLConnectionFactory.getConnection();
		Statement mainSt = mainCnt.getStatement();
		ResultSet mainRs = mainCnt.executeQuery(query, mainSt);

		try {
			while (mainRs.next()) {

				String type = mainRs.getString(BiomajSQLQuerier.MESSAGE_TYPE);
				String description = StringEscapeUtils.escapeXml(mainRs.getString(BiomajSQLQuerier.MESSAGE));
				int idMessage = mainRs.getInt(BiomajSQLQuerier.MESSAGE_ID);
				
				
				query = "SELECT ref_idsession FROM session_has_message WHERE ref_idmessage=" + idMessage;
				Statement stat = connection.getStatement();
				ResultSet rs = connection.executeQuery(query, stat);
				if (rs.next()) {
					List<String> ls = BiomajSQLQuerier.getSessionBankAndDate(rs.getLong(1));
					actualMessages++;
					xmlOutput.append("<record iderror=\"" + id++ + "\" bank=\"" + ls.get(0) + "\" " +
							"type=\"" + type + "\" source=\"Session\" " + "log=\"" + getLogFromSessionId(rs.getLong(1), connection) + "\" " +
							"message=\"" + description + "\" date=\"" + ls.get(1) + "\" />");
					SQLConnectionFactory.closeConnection(stat);
				} else {
					SQLConnectionFactory.closeConnection(stat);
					query = "SELECT ref_idsessionTask FROM sessionTask_has_message WHERE ref_idmessage=" + idMessage;
					stat = connection.getStatement();
					rs = connection.executeQuery(query, stat);
					if (rs.next()) {
						int taskId = rs.getInt(1);
						List<String> ls = BiomajSQLQuerier.getTaskBankAndDate(taskId);
						actualMessages++;
						query = "SELECT taskType FROM sessionTask WHERE idsessionTask=" + taskId;
						rs = connection.executeQuery(query, stat);
						rs.next();
						String taskType = rs.getString(1);
						
						xmlOutput.append("<record iderror=\"" + id++ + "\" bank=\"" + ls.get(0) + "\" " +
								"type=\"" + type + "\" source=\"" + taskType + "\" " + "log=\"" + getLogFromTaskId(taskId, connection) + "\" " +
								"message=\"" + description + "\" date=\"" + ls.get(1) + "\" />");
						SQLConnectionFactory.closeConnection(stat);
					} else {
						SQLConnectionFactory.closeConnection(stat);
						query = "SELECT ref_idprocess FROM process_has_message WHERE ref_idmessage=" + idMessage;
						stat = connection.getStatement();
						rs = connection.executeQuery(query, stat);
						if (rs.next()) {
							List<String> ls = BiomajSQLQuerier.getProcessBankAndDate(rs.getInt(1));
							actualMessages++;
							xmlOutput.append("<record iderror=\"" + id++ + "\" bank=\"" + ls.get(0) + "\" " +
									"type=\"" + type + "\" source=\"Process\" " + "log=\"" + getLogFromProcessId(rs.getInt(1), connection) + "\" " +
									"message=\"" + description + "\" date=\"" + ls.get(1) + "\" />");
							SQLConnectionFactory.closeConnection(stat);
						} else {
							SQLConnectionFactory.closeConnection(stat);
							query = "SELECT ref_idmetaprocess FROM metaprocess_has_message WHERE ref_idmessage=" + idMessage;
							stat = connection.getStatement();
							rs = connection.executeQuery(query, stat);
							if (rs.next()) {								
								List<String> ls = BiomajSQLQuerier.getMetaprocessBankAndDate(rs.getString(1));
								actualMessages++;
								xmlOutput.append("<record iderror=\"" + id++ + "\" bank=\"" + ls.get(0) + "\" " +
										"type=\"" + type + "\" source=\"Metaprocess\" " + "log=\"" + getLogFromMetaId(rs.getString(1), connection) + "\" " +
										"message=\"" + description + "\" date=\"" + ls.get(1) + "\" />");
							}
							SQLConnectionFactory.closeConnection(stat);
						}
					}
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		SQLConnectionFactory.closeConnection(mainSt);
		
		xmlOutput.append("</data></response>");
		String header =  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
			+ "<response>" +
			"<status>0</status>" +
			"<startRow>0</startRow>" +
			"<endRow>" + actualMessages + "</endRow>" +
			"<totalRows>" + actualMessages + "</totalRows>" +
			"<data>\n";
		
		return (header + xmlOutput.toString());
	}
	
	private static String getLogFromSessionId(long id, SQLConnection c) throws SQLException {
		Statement s = c.getStatement();
		ResultSet rs = c.executeQuery("SELECT logfile FROM session WHERE idsession=" + id, s);
		String res = "";
		if (rs.next())
			res = rs.getString(1);
		SQLConnectionFactory.closeConnection(s);
		return truncateURL(res);
	}
	
	private static String getLogFromTaskId(long id, SQLConnection c) throws SQLException {
		Statement s = c.getStatement();
		ResultSet rs = c.executeQuery("SELECT logfile FROM session WHERE idsession=(" +
				"SELECT ref_idsession FROM session_has_sessionTask WHERE ref_idsessionTask=" + id + ")", s);
		String res = "";
		if (rs.next())
			res = rs.getString(1);
		SQLConnectionFactory.closeConnection(s);
		return truncateURL(res);
	}
	
	private static String getLogFromMetaId(String id, SQLConnection c) throws SQLException {
		Statement s = c.getStatement();
		ResultSet rs = c.executeQuery("SELECT logfile FROM metaprocess WHERE idmetaprocess='" + id + "'", s);
		String res = "";
		if (rs.next())
			res = rs.getString(1);
		SQLConnectionFactory.closeConnection(s);
		return truncateURL(res);
	}
	
	private static String getLogFromProcessId(long id, SQLConnection c) throws SQLException {
		Statement s = c.getStatement();
		ResultSet rs = c.executeQuery("SELECT logfile FROM metaprocess WHERE idmetaprocess=(" +
				"SELECT ref_idmetaprocess FROM process WHERE idprocess=" + id + ")", s);
		String res = "";
		if (rs.next())
			res = rs.getString(1);
		SQLConnectionFactory.closeConnection(s);
		return truncateURL(res);
	}
	
	/**
	 * Returns the url in the right format to be browsable by tomcat.
	 * 
	 * @return
	 */
	private static String truncateURL(String _url) {
		if (!_url.trim().isEmpty()) {
			String url = _url;
			// Get the 3 last /
			url = url.substring(0, url.lastIndexOf('/'));
			url = url.substring(0, url.lastIndexOf('/'));
			int index = url.lastIndexOf('/') + 1;
			
			return "logs/" + _url.substring(index);
		}
		return "";
	}
}
