<commit_before>package database;

import java.security.acl.Owner;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import server.ConfigurationProperties;
import server.InputValidator;
import server.PasswordHasher;
import dto.CandidateDto;
import dto.ElectionDto;
import dto.InputValidation;
import dto.SecurityValidator;
import dto.UserDto;
import dto.Validator;
import dto.VoteDto;
import enumeration.Status;
import enumeration.ElectionStatus;

public class DatabaseConnector {
	private static String dbHost;
	private static String dbPort;
	private static String dbUser;
	private static String dbPassword;
	private static String dbName;
	private Connection con;
	
	public DatabaseConnector() {
		Connection con = null;
		
		//System.out.println(ConfigurationProperties.dbHost());

		dbHost = ConfigurationProperties.dbHost();
		dbPort = ConfigurationProperties.dbPort();
		dbName = ConfigurationProperties.dbSchema();
		dbUser = ConfigurationProperties.dbUser();
		dbPassword = ConfigurationProperties.dbPassword();
		
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
			String url = "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName;
			con = DriverManager.getConnection(url, dbUser,
					dbPassword);
			this.con = con;
		} catch (Exception e) {
			System.out.println("Db connection failed");
			e.printStackTrace();
		}

		
	}
		
	
	public UserDto selectUserById(int userId) {
		UserDto u = new UserDto();
		
		PreparedStatement st = null;
		String query = "SELECT * FROM users WHERE user_id = ?";
		
		try {
			st = con.prepareStatement(query);
			st.setInt(1, userId);
			ResultSet res = st.executeQuery();

			if (res.next()) {
				u.setUser_id(res.getInt(1));
				u.setFirst_name(res.getString(2));
				u.setLast_name(res.getString(3));
				u.setEmail(res.getString(4));
				u.setPassword(res.getString(5));
				u.setSalt(res.getString(6));
				u.setTemp_password(res.getString(7));
				u.setTemp_salt(res.getString(8));
				u.setActivation_code(res.getString(9));
				u.setPublic_key(res.getString(10));
				u.setAdministrator_flag(res.getInt(11));
				u.setStatus(res.getInt(12));				
			}
		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		return u;
	}
	
	public Validator checkIfUsernamePasswordMatch(String email, String plainPass) {
		// 1. validate input
		Validator result = validateEmailAndPlainInput(email, plainPass);
		if (!result.isVerified()) {
			return result;
		}

		// 2. validate email
		result = verifyUserEmail(email);
		if (!result.isVerified()) {
			return result;
		}

		InputValidator iv = new InputValidator();
		PasswordHasher hasher = new PasswordHasher();

		// get this user limited info from the database
		UserDto userDto = selectUserByEmailLimited(email);

		String dbHash = userDto.getPassword();
		String dbSalt = userDto.getSalt();
		int statusId = userDto.getStatus();
		//int falseLogins = user.getFalseLogins();
		int id = userDto.getUser_id();

		// 3. check if this user is active
//		if (statusId != Enumeration.User.USER_STATUSID_ACTIVE) {
//			result.setVerified(false);
//			result.setStatus("Error, cannot login, this user account has been locked");
//			return result;
//		}

		String plainHash = hasher.sha512(plainPass, dbSalt);

		// 4. if entered password is correct, return true with welcome message
		if (plainHash.equals(dbHash)) {

			//updateDatabaseIntField("USERS", "ID", "FALSELOGINS", id, 0);
			//unsetActivationCodeAndTempPassword(id);
			result.setObject(userDto);
			result.setVerified(true);
			result.setStatus("Welcome to Certus");

			//LoggerCustom.logLoginActivity(email, "Login Successful");

			return result;
		} else {
			// 5. else record the failed login attempt
//			int newFalseLogins = falseLogins + 1;
//			updateDatabaseIntField("USERS", "ID", "FALSELOGINS", id,
//					newFalseLogins);
//
//			// if we reached the max of failed logins, lock the account, sent an
//			// email
//			if (newFalseLogins == Enumeration.User.USER_MAX_LOGIN_ATTEMPTS) {
//				// lock
//				updateDatabaseIntField("USERS", "ID", "STATUSID", id,
//						Enumeration.User.USER_STATUSID_LOCKED);
//
//				// generate activation code
//				String activationCode = setActivationCode(id);
//
//				// send email with activation code
//				SendEmail.sendEmailNotification(email,
//						Enumeration.Strings.ACCOUNT_LOCKED_SUBJECT,
//						Enumeration.Strings.ACCOUNT_LOCKED_MESSAGE
//								+ activationCode);
//
//				LoggerCustom.logLoginActivity(email, "Account locked");
//
//				result.setVerified(false);
//				result.setStatus("Error, exceeded the maximum number of login attempts, this user account has been locked");
//				return result;
//			} else {
//				result.setVerified(false);
//				result.setStatus("Error, the system could not resolve the provided combination of username and password.");
//				return result;
//			}
			
			result.setVerified(false);
			result.setStatus("Error, the system could not resolve the provided combination of username and password.");
			return result;
		}

	}
	
	public Validator validateEmailAndPlainInput(String email, String plainPass) {
		InputValidator iv = new InputValidator();
		Validator vResult = new Validator();
		Validator vEmail, vPlain;
		Boolean verified = true;
		String status = "";

		// 1. email
		vEmail = iv.validateEmail(email, "Email");
		verified &= vEmail.isVerified();
		status += vEmail.getStatus();

		// 2. plain
		vPlain = iv.validateString(plainPass, "Password");
		verified &= vPlain.isVerified();
		status += vPlain.getStatus();

		vResult.setVerified(verified);
		vResult.setStatus(status);

		return vResult;
	}
	
	public Validator verifyUserEmail(String emailToSelect) {
		Validator v = new Validator();
		v.setVerified(false);
		v.setStatus("Error, the system could not resolve the provided combination of username and password.");

		PreparedStatement st = null;
		String query = "SELECT user_id FROM users WHERE email = ?";

		try {
			st = con.prepareStatement(query);
			st.setString(1, emailToSelect);

			ResultSet res = st.executeQuery();

			if (res.next()) {
				v.setVerified(true);
				v.setStatus("");
				return v;
			}
		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}

		return v;
	}

	public UserDto selectUserByEmailLimited(String emailToSelect) {
		UserDto userDto = new UserDto();

		PreparedStatement st = null;

		String query = "SELECT user_id, first_name, last_name, password, salt, status FROM users WHERE email = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setString(1, emailToSelect);

			ResultSet res = st.executeQuery();

			if (res.next()) {
				int user_id = res.getInt(1);
				String first_name = res.getString(2);
				String last_name = res.getString(3);
				String password = res.getString(4);
				String salt = res.getString(5);
				
				int statusId = res.getInt(6);
				
//				String salt = res.getString(2);
//				
//				int falseLogins = res.getInt(4);
//				int id = res.getInt(5);
//				int roleId = res.getInt(6);
//				String acticationCode = res.getString(7);
//				String activationCodeSalt = res.getString(8);
//				String tempPassword = res.getString(9);
//				String tempPasswordSalt = res.getString(10);
//				int firmId = res.getInt(11);

				userDto.setUser_id(user_id);
				userDto.setFirst_name(first_name);
				userDto.setLast_name(last_name);
				userDto.setPassword(password);
				userDto.setSalt(salt);
				userDto.setStatus(statusId);
				
			} else {

			}

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}

		return userDto;
	}
	
	// Election
	/**
	 * @param id(int) - Election identification number (primary key)
	 * @return Validator : ElectionDto - Details of a particular election
	 * @author <NAME>
	 */
	public Validator selectElection(int id)
	{
		Validator validator = new Validator();
		ElectionDto electionDto = new ElectionDto();
		
		PreparedStatement st = null;

		String query = "SELECT election_id, election_name, start_datetime, close_datetime, status, s.code, s.description, owner_id "
				+ " FROM election e "
				+ " INNER JOIN status_election s "
				+ " ON (e.status = s.status_id) "
				+ " WHERE election_id = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, id);

			ResultSet res = st.executeQuery();

			if (res.next()) {
				int electionId = res.getInt(1);
				String electionName = res.getString(2);
				Timestamp startDatetime = res.getTimestamp(3);
				Timestamp closeDatetime = res.getTimestamp(4);
				int statusId = res.getInt(5);
				String statusCode = res.getString(6);
				String statusDescription = res.getString(7);
				int ownerId = res.getInt(8);

				electionDto.setElectionId(electionId);
				electionDto.setElectionName(electionName);
				electionDto.setStartDatetime(startDatetime);
				electionDto.setCloseDatetime(closeDatetime);
				electionDto.setStatus(statusId);
				electionDto.setStatusCode(statusCode);
				electionDto.setStatusDescription(statusDescription);
				electionDto.setOwnerId(ownerId);
				
			} else {

			}

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		validator.setObject(electionDto);
		return validator;
	}
	
	/**
	 * @param status(ElectionStatus) - specific status to be searched
	 * @return Validator : ArrayList<ElectionDto> - List of elections that matches a specific status
	 * @author <NAME>
	 */
	public Validator selectElections(ElectionStatus electionStatus)
	{
		Validator validator = new Validator();
		ArrayList<ElectionDto> elections = new ArrayList<ElectionDto>();
		
		PreparedStatement st = null;

		String query = "SELECT election_id, election_name, start_datetime, close_datetime, status, s.code, s.description, owner_id"
				+ " FROM election e"
				+ " INNER JOIN status_election s "
				+ " ON (e.status = s.status_id) " 
				+ " WHERE status = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, electionStatus.getCode());

			ResultSet res = st.executeQuery();

			while (res.next()) {

				int electionId = res.getInt(1);
				String electionName = res.getString(2);
				Timestamp startDatetime = res.getTimestamp(3);
				Timestamp closeDatetime = res.getTimestamp(4);
				int statusId = res.getInt(5);
				String statusCode = res.getString(6);
				String statusDescription = res.getString(7);
				int ownerId = res.getInt(8);
				
				ElectionDto electionDto = new ElectionDto();
				electionDto.setElectionId(electionId);
				electionDto.setElectionName(electionName);
				electionDto.setStartDatetime(startDatetime);
				electionDto.setCloseDatetime(closeDatetime);
				electionDto.setStatus(statusId);
				electionDto.setStatusCode(statusCode);
				electionDto.setStatusDescription(statusDescription);
				electionDto.setOwnerId(ownerId);
				
				elections.add(electionDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		validator.setObject(elections);
		return validator;
		
	}
	
	/**
	 * @param electionOwnerId(int) - user_id of the user who owns this election
	 * @param status(ElectionStatus) - specific status to be searched
	 * @return Validator : ArrayList<ElectionDto> - List of elections owned by the specific user, that matches a specific status
	 * @author <NAME>
	 */
	public Validator selectElectionsOwnedByUser(int electionOwnerId, ElectionStatus electionStatus)
	{
		Validator validator = new Validator();
		ArrayList<ElectionDto> elections = new ArrayList<ElectionDto>();
		
		PreparedStatement st = null;

		String query = "SELECT election_id, election_name, start_datetime, close_datetime, status, s.code, s.description, owner_id"
				+ " FROM election e"
				+ " INNER JOIN status_election s "
				+ " ON (e.status = s.status_id) " 
				+ " WHERE owner_id = ?"
				+ " AND status = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, electionOwnerId);
			st.setInt(2, electionStatus.getCode());

			ResultSet res = st.executeQuery();

			while (res.next()) {

				int electionId = res.getInt(1);
				String electionName = res.getString(2);
				Timestamp startDatetime = res.getTimestamp(3);
				Timestamp closeDatetime = res.getTimestamp(4);
				int statusId = res.getInt(5);
				String statusCode = res.getString(6);
				String statusDescription = res.getString(7);
				int ownerId = res.getInt(8);
				
				ElectionDto electionDto = new ElectionDto();
				electionDto.setElectionId(electionId);
				electionDto.setElectionName(electionName);
				electionDto.setStartDatetime(startDatetime);
				electionDto.setCloseDatetime(closeDatetime);
				electionDto.setStatus(statusId);
				electionDto.setStatusCode(statusCode);
				electionDto.setStatusDescription(statusDescription);
				electionDto.setOwnerId(ownerId);
				
				elections.add(electionDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		validator.setObject(elections);
		return validator;
		
	}
	
	/**
	 * @return Validator : ArrayList<ElectionDto>  - List of all the elections (regardless of status)
	 * @author <NAME>
	 */
	public Validator selectElections()
	{
		Validator validator = new Validator();
		ArrayList<ElectionDto> elections = new ArrayList<ElectionDto>();
		
		PreparedStatement st = null;

		String query = "SELECT election_id, election_name, start_datetime, close_datetime, status, s.code, s.description, owner_id"
				+ " FROM election e"
				+ " INNER JOIN status_election s "
				+ " ON (e.status = s.status_id) " ;

		try {
			st = this.con.prepareStatement(query);

			ResultSet res = st.executeQuery();

			while (res.next()) {

				int electionId = res.getInt(1);
				String electionName = res.getString(2);
				Timestamp startDatetime = res.getTimestamp(3);
				Timestamp closeDatetime = res.getTimestamp(4);
				int statusId = res.getInt(5);
				String statusCode = res.getString(6);
				String statusDescription = res.getString(7);
				int ownerId = res.getInt(8);
				
				ElectionDto electionDto = new ElectionDto();
				electionDto.setElectionId(electionId);
				electionDto.setElectionName(electionName);
				electionDto.setStartDatetime(startDatetime);
				electionDto.setCloseDatetime(closeDatetime);
				electionDto.setStatus(statusId);
				electionDto.setStatusCode(statusCode);
				electionDto.setStatusDescription(statusDescription);
				electionDto.setOwnerId(ownerId);
				
				elections.add(electionDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		validator.setObject(elections);
		return validator;
		
	}
	
	/**
	 * @param election_owner_id(int) - user_id of the user who owns elections
	 * @return Validator : ArrayList<ElectionDto> - List of all the elections owned by the specific user (regardless of status)
	 * @author <NAME>
	 */
	public Validator selectElectionsOwnedByUser(int electionOwnerId)
	{
		Validator validator = new Validator();
		ArrayList<ElectionDto> elections = new ArrayList<ElectionDto>();
		
		PreparedStatement st = null;

		String query = "SELECT election_id, election_name, start_datetime, close_datetime, status, s.code, s.description, owner_id"
				+ " FROM election e"
				+ " INNER JOIN status_election s "
				+ " ON (e.status = s.status_id) "
				+ " WHERE owner_id = ?" ;

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, electionOwnerId);

			ResultSet res = st.executeQuery();

			while (res.next()) {

				int electionId = res.getInt(1);
				String electionName = res.getString(2);
				Timestamp startDatetime = res.getTimestamp(3);
				Timestamp closeDatetime = res.getTimestamp(4);
				int statusId = res.getInt(5);
				String statusCode = res.getString(6);
				String statusDescription = res.getString(7);
				int ownerId = res.getInt(8);
				
				ElectionDto electionDto = new ElectionDto();
				electionDto.setElectionId(electionId);
				electionDto.setElectionName(electionName);
				electionDto.setStartDatetime(startDatetime);
				electionDto.setCloseDatetime(closeDatetime);
				electionDto.setStatus(statusId);
				electionDto.setStatusCode(statusCode);
				electionDto.setStatusDescription(statusDescription);
				electionDto.setOwnerId(ownerId);
				
				elections.add(electionDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		validator.setObject(elections);
		return validator;
		
	}
	// Candidates
	/**
	 * @param id - candidate identification number (primary key)
	 * @return Validator :CandidateDto - Details of a particular candidate
	 * @author <NAME>
	 */
	public Validator selectCandidate(int id)
	{
		Validator validator = new Validator();
		CandidateDto candidateDto = new CandidateDto();
		
		PreparedStatement st = null;

		String query = "SELECT candidate_id, candidate_name, election_id, display_order, status FROM candidate WHERE candidate_id = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, id);

			ResultSet res = st.executeQuery();

			if (res.next()) {
				
				int candidateId = res.getInt(1);
				String candidate_name = res.getString(2);
				int electionId = res.getInt(3);
				int displayOrder = res.getInt(4);
				int statusId = res.getInt(5);

				candidateDto.setCandidateId(candidateId);
				candidateDto.setCandidateName(candidate_name);
				candidateDto.setElectionId(electionId);
				candidateDto.setDisplayOrder(displayOrder);
				candidateDto.setStatus(statusId);
				
			} else {

			}

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		validator.setObject(candidateDto);
		return validator;
	}
	
	/**
	 * @param electionIdKey - election identification number
	 * @return Validator : ArrayList<CandidateDto>- list of all the candidates under specified election
	 * @author <NAME>
	 */
	public Validator selectCandidatesOfElection(int electionIdKey)
	{
		Validator validator = new Validator();
		ArrayList<CandidateDto> candidates = new ArrayList<CandidateDto>();
		
		PreparedStatement st = null;

		String query = "SELECT candidate_id, candidate_name, election_id, display_order, status FROM candidate WHERE election_id = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, electionIdKey);

			ResultSet res = st.executeQuery();

			while (res.next()) {

				int candidateId = res.getInt(1);
				String candidateName = res.getString(2);
				int electionId = res.getInt(3);
				int displayOrder = res.getInt(4);
				int statusId = res.getInt(5);

				CandidateDto candidateDto = new CandidateDto();
				candidateDto.setCandidateId(candidateId);
				candidateDto.setCandidateName(candidateName);
				candidateDto.setElectionId(electionId);
				candidateDto.setDisplayOrder(displayOrder);
				candidateDto.setStatus(statusId);
				
				candidates.add(candidateDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		validator.setObject(candidates);
		return validator;
	}
	
	/**
	 * @param electionIdKey - election identification number
	 * @param candidateStatus - desired status of candidate which required to be returned for given election
	 * @return Validator :ArrayList<CandidateDto> - list of all the candidates that matches the status under specified election
	 * @author <NAME>
	 */
	public Validator selectCandidatesOfElection(int electionIdKey, Status candidateStatus)
	{
		Validator validator = new Validator();
		ArrayList<CandidateDto> candidates = new ArrayList<CandidateDto>();
		
		PreparedStatement st = null;

		String query = "SELECT candidate_id, candidate_name, election_id, display_order, status "
						+ "	FROM candidate "
						+ " WHERE election_id = ?"
						+ " AND status = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, electionIdKey);
			st.setInt(2, candidateStatus.getCode());
			
			ResultSet res = st.executeQuery();

			while (res.next()) {

				int candidateId = res.getInt(1);
				String candidateName = res.getString(2);
				int electionId = res.getInt(3);
				int displayOrder = res.getInt(4);
				int statusId = res.getInt(5);

				CandidateDto candidateDto = new CandidateDto();
				candidateDto.setCandidateId(candidateId);
				candidateDto.setCandidateName(candidateName);
				candidateDto.setElectionId(electionId);
				candidateDto.setDisplayOrder(displayOrder);
				candidateDto.setStatus(statusId);
				
				candidates.add(candidateDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		validator.setObject(candidates);
		return validator;
	}
	
	
	/**
	 * @param name - election name
	 * Add new election to db
	 * @author <NAME>
	 */
	public Validator createNewElection(ElectionDto electionDto){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val=new Validator();
		
		try{
			val=iv.validateString(electionDto.getElectionName(), "Election name");
			if(val.isVerified()){
				String query = "INSERT INTO election (election_name, status, owner_id) VALUES (?,?,?)";
				int status=ElectionStatus.NEW.getCode();
				st=this.con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
				st.setString(1, electionDto.getElectionName());
				st.setInt(2, status);
				st.setInt(3, electionDto.getOwnerId());
				int id=st.executeUpdate();
				val.setStatus("Election added to DB");
				electionDto.setElectionId(id);
				val.setObject(electionDto);
				return val;
			}
			else{
				val.setStatus("Name failed to validate");
				return val;
			}
		}
		catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL error");
			return val;
		}
	}
	
	/**
	 * @param candidateList - candidate array list 
	 * @param election_id - the election to add candidates to
	 * Add candidates to an election
	 * @author <NAME>
	 */
	public Validator addCandidatesToElection(ArrayList<CandidateDto> candidateList, int election_id){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val = new Validator();
		boolean aOK=true;
		try{
			for(int i=0;i<candidateList.size();i++){
				val = iv.validateString(candidateList.get(i).getCandidateName(), "Candidate Name");
				aOK&=val.isVerified();
			}
			if(aOK){
				for(int i=0;i<candidateList.size();i++){
					String query="INSERT INTO candidates (candidate_name, election_id, status) VALUES (?,?,?)";
					st=this.con.prepareStatement(query,Statement.RETURN_GENERATED_KEYS);
					st.setString(1,candidateList.get(i).getCandidateName());
					st.setInt(2, election_id);
					st.setInt(3, Status.ENABLED.getCode());
					int id=st.executeUpdate();
					candidateList.get(i).setCandidateId(id);
				}
				val.setStatus("Candidates added to DB");
				val.setObject(candidateList);
			}
			else{
				val.setStatus("Candidate names failed to validate");
			}
			val.setVerified(aOK);
			return val;
			
		}
		catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setVerified(false);
			val.setStatus("SQL Error");
			return val;
		}
	}
	
	/**
	 * @param candidateDto - candidate object
	 * @author <NAME>
	 */
	public Validator editCandidate(CandidateDto candidateDto){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val = new Validator();
		try{
			val = iv.validateString(candidateDto.getCandidateName(), "Candidate Name");
			boolean valid=true;
			valid&=val.isVerified();
			val=iv.validateInt(candidateDto.getDisplayOrder(), "Display Order");
			valid&=val.isVerified();
			if(valid){
				String query="UPDATE candidate SET (candidate_name, display_order)=(?,?) WHERE candidate_id=?";
				st=this.con.prepareStatement(query);
				st.setString(1, candidateDto.getCandidateName());
				st.setInt(2, candidateDto.getDisplayOrder());
				st.setInt(3,candidateDto.getCandidateId());
				st.execute();
				val.setStatus("Candidate information updated");
				return val;
			}
			else{
				val.setStatus("Candidate information did not validate");
				val.setVerified(false);
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
		
	}
	
	public Validator editCandidateStatus(CandidateDto cand){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val = new Validator();
		try{
			val = iv.validateInt(cand.getStatus(), "Candidate Status");
			if(val.isVerified()){
				String query="UPDATE candidate SET status=? WHERE candidate_id=?";
				st=this.con.prepareStatement(query);
				st.setInt(1, cand.getCandidateId());
				st.execute();
				val.setStatus("Candidate status updated");
				return val;
			}
			else{
				val.setStatus("Status failed to verify");
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	/**
	 * @param electionId - the election to open
	 * Add candidates to an election
	 * @author <NAME>
	 */
	public Validator openElection(int electionId){
		PreparedStatement st=null;
		Validator val=new Validator();
		
		try{
			String query="UPDATE election"
					+ " SET status="+ElectionStatus.NEW.getCode()
					+ " WHERE election_id="+electionId;
			st=this.con.prepareStatement(query);
			st.execute();
			val.setVerified(true);
			val.setStatus("Election opened");
			return val;
		}
		catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	/**
	 * @param electionId - the election to close
	 * Close an election
	 * @author <NAME>
	 */
	public Validator closeElection(int electionId){
		PreparedStatement st=null;
		Validator val=new Validator();
		try{
			String query="UPDATE election"
					+ " SET status="+ ElectionStatus.CLOSED.getCode()
					+ " WHERE election_id="+electionId;
			st=this.con.prepareStatement(query);
			st.execute();
			val.setVerified(true);
			val.setStatus("Election closed");
			return val;
		}
		catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setVerified(false);
			val.setStatus("SQL Error");
			return val;
		}
	}
	
	/**
	 * @param electionId - the election to delete
	 * Delete an election
	 * @author <NAME>
	 */
	public Validator deleteElection(int electionId){
		PreparedStatement st=null;
		Validator val=new Validator();
		try{
			String query="UPDATE election SET status=7 WHERE election_id="+electionId;
			st=this.con.prepareStatement(query);
			st.execute();
			val.setStatus("Election deleted");
			val.setVerified(true);
			return val;
		}
		catch(SQLException ex){
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	/**
	 * @param electionId - the election id to update the status
	 * Delete an election
	 * @author <NAME>
	 */
	public Validator editElectionStatus(int electionId, ElectionStatus electionStatus){
		PreparedStatement st=null;
		Validator val=new Validator();
		try{
			String query="UPDATE election"
					+ " SET status="+electionStatus.getCode()
					+ " WHERE election_id="+electionId;
			st=this.con.prepareStatement(query);
			st.execute();
			val.setStatus("Election status updated");
			val.setVerified(true);
			return val;
		}
		catch(SQLException ex){
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	/**
	 * @param electionDto - the election to edit
	 * Edit an election
	 * @author <NAME>
	 */
	public Validator editElection(ElectionDto electionDto){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val = new Validator();
		try{
			val = iv.validateString(electionDto.getElectionName(), "Election Name");
			if(val.isVerified()){
				String query="UPDATE election SET election_name=? WHERE election_id=?";
				st=this.con.prepareStatement(query);
				st.setString(1, electionDto.getElectionName());
				st.setInt(2,electionDto.getElectionId());
				st.execute();
				val.setStatus("Election updated successfully");
				return val;
			}
			else{
				val.setStatus("New election name did not validate");
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	//Vote
	
	/**
	 * @param voteDto - the vote to submit
	 * Submit a vote
	 * @author <NAME>
	 */
	
	public Validator vote(VoteDto voteDto){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val=new Validator();
		boolean valid=true;
		val=iv.validateInt(voteDto.getUser_id(), "User ID");
		valid&=val.isVerified();
		val=iv.validateInt(voteDto.getElection_id(), "Election ID");
		valid&=val.isVerified();
		val=iv.validateString(voteDto.getVote_encrypted(), "Encrypted Vote");
		SecurityValidator sec=new SecurityValidator();
		try{
			if(valid && sec.checkSignature(voteDto.getVote_signature(), voteDto.getUser_id()).isVerified()){
				String query="INSERT INTO vote (user_id, election_id, vote_encrypted, vote_signature)"
						+ " VALUES (?,?,?,?)";
				st=this.con.prepareStatement(query);
				st.setInt(1, voteDto.getUser_id());
				st.setInt(2, voteDto.getElection_id());
				st.setString(3, voteDto.getVote_encrypted());
				st.setString(4, voteDto.getVote_signature());
				st.execute();
				val.setStatus("Vote successfully cast");
				val.setVerified(true);
				return val;
			}
			else{
				val.setStatus("Information did not validate");
				val.setVerified(false);
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	public Validator getPubKeyByUserID(int userId){
		PreparedStatement st = null;
		Validator val=new Validator();
		InputValidation iv=new InputValidation();
		val=iv.validateInt(userId, "User ID");
		String query = "SELECT public_key FROM users WHERE user_id = ?";
		try{
			if(val.isVerified()){
				st = this.con.prepareStatement(query);
				st.setInt(1, userId);
				ResultSet res=st.executeQuery();
				if (res.next()) {
					String pubKey = res.getString(1);
					val.setObject(pubKey);
					val.setStatus("Public key retrieved");
					return val;
				}
				else{
					val.setVerified(false);
					val.setStatus("No public key for this user id");
					return val;
				}
			}
			else{
				val.setStatus("User ID did not validate");
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setVerified(false);
			val.setStatus("SQL Error");
			return val;
		}
	}
	
	public Validator selectVotesByElectionId(int election_id){
		Validator val=new Validator();
		InputValidation iv=new InputValidation();
		ArrayList<VoteDto> votes=new ArrayList<VoteDto>();
		val=iv.validateInt(election_id, "Election ID");
		PreparedStatement st=null;
		try{
			if(val.isVerified()){
				String query="SELECT user_id, vote_encrypted, vote_signature, timestamp "
							+ "	FROM vote "
							+ " WHERE election_id = ?";
				st = this.con.prepareStatement(query);
				st.setInt(1, election_id);
				ResultSet res=st.executeQuery();
				while (res.next()) {
					int user_id = res.getInt(1);
					String vote_encrypted = res.getString(2);
					String vote_signature = res.getString(3);
					Timestamp t = res.getTimestamp(4);

					VoteDto vote = new VoteDto();
					vote.setUser_id(user_id);
					vote.setVote_encrypted(vote_encrypted);
					vote.setVote_signature(vote_signature);
					vote.setElection_id(election_id);
					vote.setTimestamp(t);
					
					votes.add(vote);
				}
				val.setStatus("Successfully retrieved votes");
				val.setObject(votes);
				return val;
			}
			else{
				val.setStatus("Election ID failed to validate");
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setVerified(false);
			val.setStatus("SQL Error");
			return val;
		}
	}
	
	public Validator tally(int election_id){
		Map<CandidateDto, Integer> t= new HashMap<CandidateDto, Integer>();
		PreparedStatement st=null;
		Validator val=new Validator();
		InputValidation iv = new InputValidation();
		SecurityValidator sec=new SecurityValidator();
		val=iv.validateInt(election_id, "Election ID");
		if(val.isVerified()){
			Validator voteVal=selectVotesByElectionId(election_id);
			
			if(voteVal.isVerified()){
				ArrayList<VoteDto> votes = (ArrayList<VoteDto>)voteVal.getObject();
				for(int i =0;i<votes.size();i++){
					String enc=votes.get(i).getVote_encrypted();
					String sig=votes.get(i).getVote_signature();
					if(sec.checkSignature(sig, votes.get(i).getUser_id()).isVerified()){
						int cand_id=Integer.parseInt(sec.decrypt(enc, getTallierSecretKey()), 16);
						CandidateDto cand=(CandidateDto)selectCandidate(cand_id).getObject();
						if(t.containsKey(cand)){
							int total=t.get(cand);
							total+=1;
							t.remove(cand);
							t.put(cand, total);
						}
						else{
							t.put(cand, 1);
						}
					}
					
				}
				val.setStatus("Tally computed");
				val.setObject(t);
				return val;
			}
			else{
				val.setStatus(voteVal.getStatus());
				val.setVerified(voteVal.isVerified());
				return val;
			}
		}
		else{
			val.setStatus("Election ID failed to verify");
			return val;
		}
	}
}<commit_msg>Inserted Id fixed<commit_after>package database;

import java.security.acl.Owner;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import server.ConfigurationProperties;
import server.InputValidator;
import server.PasswordHasher;
import dto.CandidateDto;
import dto.ElectionDto;
import dto.InputValidation;
import dto.SecurityValidator;
import dto.UserDto;
import dto.Validator;
import dto.VoteDto;
import enumeration.Status;
import enumeration.ElectionStatus;

public class DatabaseConnector {
	private static String dbHost;
	private static String dbPort;
	private static String dbUser;
	private static String dbPassword;
	private static String dbName;
	private Connection con;
	
	public DatabaseConnector() {
		Connection con = null;
		
		//System.out.println(ConfigurationProperties.dbHost());

		dbHost = ConfigurationProperties.dbHost();
		dbPort = ConfigurationProperties.dbPort();
		dbName = ConfigurationProperties.dbSchema();
		dbUser = ConfigurationProperties.dbUser();
		dbPassword = ConfigurationProperties.dbPassword();
		
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
			String url = "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + dbName;
			con = DriverManager.getConnection(url, dbUser,
					dbPassword);
			this.con = con;
		} catch (Exception e) {
			System.out.println("Db connection failed");
			e.printStackTrace();
		}

		
	}
		
	
	public UserDto selectUserById(int userId) {
		UserDto u = new UserDto();
		
		PreparedStatement st = null;
		String query = "SELECT * FROM users WHERE user_id = ?";
		
		try {
			st = con.prepareStatement(query);
			st.setInt(1, userId);
			ResultSet res = st.executeQuery();

			if (res.next()) {
				u.setUser_id(res.getInt(1));
				u.setFirst_name(res.getString(2));
				u.setLast_name(res.getString(3));
				u.setEmail(res.getString(4));
				u.setPassword(res.getString(5));
				u.setSalt(res.getString(6));
				u.setTemp_password(res.getString(7));
				u.setTemp_salt(res.getString(8));
				u.setActivation_code(res.getString(9));
				u.setPublic_key(res.getString(10));
				u.setAdministrator_flag(res.getInt(11));
				u.setStatus(res.getInt(12));				
			}
		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		return u;
	}
	
	public Validator checkIfUsernamePasswordMatch(String email, String plainPass) {
		// 1. validate input
		Validator result = validateEmailAndPlainInput(email, plainPass);
		if (!result.isVerified()) {
			return result;
		}

		// 2. validate email
		result = verifyUserEmail(email);
		if (!result.isVerified()) {
			return result;
		}

		InputValidator iv = new InputValidator();
		PasswordHasher hasher = new PasswordHasher();

		// get this user limited info from the database
		UserDto userDto = selectUserByEmailLimited(email);

		String dbHash = userDto.getPassword();
		String dbSalt = userDto.getSalt();
		int statusId = userDto.getStatus();
		//int falseLogins = user.getFalseLogins();
		int id = userDto.getUser_id();

		// 3. check if this user is active
//		if (statusId != Enumeration.User.USER_STATUSID_ACTIVE) {
//			result.setVerified(false);
//			result.setStatus("Error, cannot login, this user account has been locked");
//			return result;
//		}

		String plainHash = hasher.sha512(plainPass, dbSalt);

		// 4. if entered password is correct, return true with welcome message
		if (plainHash.equals(dbHash)) {

			//updateDatabaseIntField("USERS", "ID", "FALSELOGINS", id, 0);
			//unsetActivationCodeAndTempPassword(id);
			result.setObject(userDto);
			result.setVerified(true);
			result.setStatus("Welcome to Certus");

			//LoggerCustom.logLoginActivity(email, "Login Successful");

			return result;
		} else {
			// 5. else record the failed login attempt
//			int newFalseLogins = falseLogins + 1;
//			updateDatabaseIntField("USERS", "ID", "FALSELOGINS", id,
//					newFalseLogins);
//
//			// if we reached the max of failed logins, lock the account, sent an
//			// email
//			if (newFalseLogins == Enumeration.User.USER_MAX_LOGIN_ATTEMPTS) {
//				// lock
//				updateDatabaseIntField("USERS", "ID", "STATUSID", id,
//						Enumeration.User.USER_STATUSID_LOCKED);
//
//				// generate activation code
//				String activationCode = setActivationCode(id);
//
//				// send email with activation code
//				SendEmail.sendEmailNotification(email,
//						Enumeration.Strings.ACCOUNT_LOCKED_SUBJECT,
//						Enumeration.Strings.ACCOUNT_LOCKED_MESSAGE
//								+ activationCode);
//
//				LoggerCustom.logLoginActivity(email, "Account locked");
//
//				result.setVerified(false);
//				result.setStatus("Error, exceeded the maximum number of login attempts, this user account has been locked");
//				return result;
//			} else {
//				result.setVerified(false);
//				result.setStatus("Error, the system could not resolve the provided combination of username and password.");
//				return result;
//			}
			
			result.setVerified(false);
			result.setStatus("Error, the system could not resolve the provided combination of username and password.");
			return result;
		}

	}
	
	public Validator validateEmailAndPlainInput(String email, String plainPass) {
		InputValidator iv = new InputValidator();
		Validator vResult = new Validator();
		Validator vEmail, vPlain;
		Boolean verified = true;
		String status = "";

		// 1. email
		vEmail = iv.validateEmail(email, "Email");
		verified &= vEmail.isVerified();
		status += vEmail.getStatus();

		// 2. plain
		vPlain = iv.validateString(plainPass, "Password");
		verified &= vPlain.isVerified();
		status += vPlain.getStatus();

		vResult.setVerified(verified);
		vResult.setStatus(status);

		return vResult;
	}
	
	public Validator verifyUserEmail(String emailToSelect) {
		Validator v = new Validator();
		v.setVerified(false);
		v.setStatus("Error, the system could not resolve the provided combination of username and password.");

		PreparedStatement st = null;
		String query = "SELECT user_id FROM users WHERE email = ?";

		try {
			st = con.prepareStatement(query);
			st.setString(1, emailToSelect);

			ResultSet res = st.executeQuery();

			if (res.next()) {
				v.setVerified(true);
				v.setStatus("");
				return v;
			}
		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}

		return v;
	}

	public UserDto selectUserByEmailLimited(String emailToSelect) {
		UserDto userDto = new UserDto();

		PreparedStatement st = null;

		String query = "SELECT user_id, first_name, last_name, password, salt, status FROM users WHERE email = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setString(1, emailToSelect);

			ResultSet res = st.executeQuery();

			if (res.next()) {
				int user_id = res.getInt(1);
				String first_name = res.getString(2);
				String last_name = res.getString(3);
				String password = <PASSWORD>.getString(4);
				String salt = res.getString(5);
				
				int statusId = res.getInt(6);
				
//				String salt = res.getString(2);
//				
//				int falseLogins = res.getInt(4);
//				int id = res.getInt(5);
//				int roleId = res.getInt(6);
//				String acticationCode = res.getString(7);
//				String activationCodeSalt = res.getString(8);
//				String tempPassword = <PASSWORD>(9);
//				String tempPasswordSalt = res.getString(10);
//				int firmId = res.getInt(11);

				userDto.setUser_id(user_id);
				userDto.setFirst_name(first_name);
				userDto.setLast_name(last_name);
				userDto.setPassword(password);
				userDto.setSalt(salt);
				userDto.setStatus(statusId);
				
			} else {

			}

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}

		return userDto;
	}
	
	// Election
	/**
	 * @param id(int) - Election identification number (primary key)
	 * @return Validator : ElectionDto - Details of a particular election
	 * @author <NAME>
	 */
	public Validator selectElection(int id)
	{
		Validator validator = new Validator();
		ElectionDto electionDto = new ElectionDto();
		
		PreparedStatement st = null;

		String query = "SELECT election_id, election_name, start_datetime, close_datetime, status, s.code, s.description, owner_id "
				+ " FROM election e "
				+ " INNER JOIN status_election s "
				+ " ON (e.status = s.status_id) "
				+ " WHERE election_id = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, id);

			ResultSet res = st.executeQuery();

			if (res.next()) {
				int electionId = res.getInt(1);
				String electionName = res.getString(2);
				Timestamp startDatetime = res.getTimestamp(3);
				Timestamp closeDatetime = res.getTimestamp(4);
				int statusId = res.getInt(5);
				String statusCode = res.getString(6);
				String statusDescription = res.getString(7);
				int ownerId = res.getInt(8);

				electionDto.setElectionId(electionId);
				electionDto.setElectionName(electionName);
				electionDto.setStartDatetime(startDatetime);
				electionDto.setCloseDatetime(closeDatetime);
				electionDto.setStatus(statusId);
				electionDto.setStatusCode(statusCode);
				electionDto.setStatusDescription(statusDescription);
				electionDto.setOwnerId(ownerId);
				
			} else {

			}

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		validator.setObject(electionDto);
		return validator;
	}
	
	/**
	 * @param status(ElectionStatus) - specific status to be searched
	 * @return Validator : ArrayList<ElectionDto> - List of elections that matches a specific status
	 * @author <NAME>
	 */
	public Validator selectElections(ElectionStatus electionStatus)
	{
		Validator validator = new Validator();
		ArrayList<ElectionDto> elections = new ArrayList<ElectionDto>();
		
		PreparedStatement st = null;

		String query = "SELECT election_id, election_name, start_datetime, close_datetime, status, s.code, s.description, owner_id"
				+ " FROM election e"
				+ " INNER JOIN status_election s "
				+ " ON (e.status = s.status_id) " 
				+ " WHERE status = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, electionStatus.getCode());

			ResultSet res = st.executeQuery();

			while (res.next()) {

				int electionId = res.getInt(1);
				String electionName = res.getString(2);
				Timestamp startDatetime = res.getTimestamp(3);
				Timestamp closeDatetime = res.getTimestamp(4);
				int statusId = res.getInt(5);
				String statusCode = res.getString(6);
				String statusDescription = res.getString(7);
				int ownerId = res.getInt(8);
				
				ElectionDto electionDto = new ElectionDto();
				electionDto.setElectionId(electionId);
				electionDto.setElectionName(electionName);
				electionDto.setStartDatetime(startDatetime);
				electionDto.setCloseDatetime(closeDatetime);
				electionDto.setStatus(statusId);
				electionDto.setStatusCode(statusCode);
				electionDto.setStatusDescription(statusDescription);
				electionDto.setOwnerId(ownerId);
				
				elections.add(electionDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		validator.setObject(elections);
		return validator;
		
	}
	
	/**
	 * @param electionOwnerId(int) - user_id of the user who owns this election
	 * @param status(ElectionStatus) - specific status to be searched
	 * @return Validator : ArrayList<ElectionDto> - List of elections owned by the specific user, that matches a specific status
	 * @author <NAME>
	 */
	public Validator selectElectionsOwnedByUser(int electionOwnerId, ElectionStatus electionStatus)
	{
		Validator validator = new Validator();
		ArrayList<ElectionDto> elections = new ArrayList<ElectionDto>();
		
		PreparedStatement st = null;

		String query = "SELECT election_id, election_name, start_datetime, close_datetime, status, s.code, s.description, owner_id"
				+ " FROM election e"
				+ " INNER JOIN status_election s "
				+ " ON (e.status = s.status_id) " 
				+ " WHERE owner_id = ?"
				+ " AND status = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, electionOwnerId);
			st.setInt(2, electionStatus.getCode());

			ResultSet res = st.executeQuery();

			while (res.next()) {

				int electionId = res.getInt(1);
				String electionName = res.getString(2);
				Timestamp startDatetime = res.getTimestamp(3);
				Timestamp closeDatetime = res.getTimestamp(4);
				int statusId = res.getInt(5);
				String statusCode = res.getString(6);
				String statusDescription = res.getString(7);
				int ownerId = res.getInt(8);
				
				ElectionDto electionDto = new ElectionDto();
				electionDto.setElectionId(electionId);
				electionDto.setElectionName(electionName);
				electionDto.setStartDatetime(startDatetime);
				electionDto.setCloseDatetime(closeDatetime);
				electionDto.setStatus(statusId);
				electionDto.setStatusCode(statusCode);
				electionDto.setStatusDescription(statusDescription);
				electionDto.setOwnerId(ownerId);
				
				elections.add(electionDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		validator.setObject(elections);
		return validator;
		
	}
	
	/**
	 * @return Validator : ArrayList<ElectionDto>  - List of all the elections (regardless of status)
	 * @author <NAME>
	 */
	public Validator selectElections()
	{
		Validator validator = new Validator();
		ArrayList<ElectionDto> elections = new ArrayList<ElectionDto>();
		
		PreparedStatement st = null;

		String query = "SELECT election_id, election_name, start_datetime, close_datetime, status, s.code, s.description, owner_id"
				+ " FROM election e"
				+ " INNER JOIN status_election s "
				+ " ON (e.status = s.status_id) " ;

		try {
			st = this.con.prepareStatement(query);

			ResultSet res = st.executeQuery();

			while (res.next()) {

				int electionId = res.getInt(1);
				String electionName = res.getString(2);
				Timestamp startDatetime = res.getTimestamp(3);
				Timestamp closeDatetime = res.getTimestamp(4);
				int statusId = res.getInt(5);
				String statusCode = res.getString(6);
				String statusDescription = res.getString(7);
				int ownerId = res.getInt(8);
				
				ElectionDto electionDto = new ElectionDto();
				electionDto.setElectionId(electionId);
				electionDto.setElectionName(electionName);
				electionDto.setStartDatetime(startDatetime);
				electionDto.setCloseDatetime(closeDatetime);
				electionDto.setStatus(statusId);
				electionDto.setStatusCode(statusCode);
				electionDto.setStatusDescription(statusDescription);
				electionDto.setOwnerId(ownerId);
				
				elections.add(electionDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		validator.setObject(elections);
		return validator;
		
	}
	
	/**
	 * @param election_owner_id(int) - user_id of the user who owns elections
	 * @return Validator : ArrayList<ElectionDto> - List of all the elections owned by the specific user (regardless of status)
	 * @author <NAME>
	 */
	public Validator selectElectionsOwnedByUser(int electionOwnerId)
	{
		Validator validator = new Validator();
		ArrayList<ElectionDto> elections = new ArrayList<ElectionDto>();
		
		PreparedStatement st = null;

		String query = "SELECT election_id, election_name, start_datetime, close_datetime, status, s.code, s.description, owner_id"
				+ " FROM election e"
				+ " INNER JOIN status_election s "
				+ " ON (e.status = s.status_id) "
				+ " WHERE owner_id = ?" ;

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, electionOwnerId);

			ResultSet res = st.executeQuery();

			while (res.next()) {

				int electionId = res.getInt(1);
				String electionName = res.getString(2);
				Timestamp startDatetime = res.getTimestamp(3);
				Timestamp closeDatetime = res.getTimestamp(4);
				int statusId = res.getInt(5);
				String statusCode = res.getString(6);
				String statusDescription = res.getString(7);
				int ownerId = res.getInt(8);
				
				ElectionDto electionDto = new ElectionDto();
				electionDto.setElectionId(electionId);
				electionDto.setElectionName(electionName);
				electionDto.setStartDatetime(startDatetime);
				electionDto.setCloseDatetime(closeDatetime);
				electionDto.setStatus(statusId);
				electionDto.setStatusCode(statusCode);
				electionDto.setStatusDescription(statusDescription);
				electionDto.setOwnerId(ownerId);
				
				elections.add(electionDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		validator.setObject(elections);
		return validator;
		
	}
	// Candidates
	/**
	 * @param id - candidate identification number (primary key)
	 * @return Validator :CandidateDto - Details of a particular candidate
	 * @author <NAME>
	 */
	public Validator selectCandidate(int id)
	{
		Validator validator = new Validator();
		CandidateDto candidateDto = new CandidateDto();
		
		PreparedStatement st = null;

		String query = "SELECT candidate_id, candidate_name, election_id, display_order, status FROM candidate WHERE candidate_id = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, id);

			ResultSet res = st.executeQuery();

			if (res.next()) {
				
				int candidateId = res.getInt(1);
				String candidate_name = res.getString(2);
				int electionId = res.getInt(3);
				int displayOrder = res.getInt(4);
				int statusId = res.getInt(5);

				candidateDto.setCandidateId(candidateId);
				candidateDto.setCandidateName(candidate_name);
				candidateDto.setElectionId(electionId);
				candidateDto.setDisplayOrder(displayOrder);
				candidateDto.setStatus(statusId);
				
			} else {

			}

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		validator.setObject(candidateDto);
		return validator;
	}
	
	/**
	 * @param electionIdKey - election identification number
	 * @return Validator : ArrayList<CandidateDto>- list of all the candidates under specified election
	 * @author <NAME>
	 */
	public Validator selectCandidatesOfElection(int electionIdKey)
	{
		Validator validator = new Validator();
		ArrayList<CandidateDto> candidates = new ArrayList<CandidateDto>();
		
		PreparedStatement st = null;

		String query = "SELECT candidate_id, candidate_name, election_id, display_order, status FROM candidate WHERE election_id = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, electionIdKey);

			ResultSet res = st.executeQuery();

			while (res.next()) {

				int candidateId = res.getInt(1);
				String candidateName = res.getString(2);
				int electionId = res.getInt(3);
				int displayOrder = res.getInt(4);
				int statusId = res.getInt(5);

				CandidateDto candidateDto = new CandidateDto();
				candidateDto.setCandidateId(candidateId);
				candidateDto.setCandidateName(candidateName);
				candidateDto.setElectionId(electionId);
				candidateDto.setDisplayOrder(displayOrder);
				candidateDto.setStatus(statusId);
				
				candidates.add(candidateDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		validator.setObject(candidates);
		return validator;
	}
	
	/**
	 * @param electionIdKey - election identification number
	 * @param candidateStatus - desired status of candidate which required to be returned for given election
	 * @return Validator :ArrayList<CandidateDto> - list of all the candidates that matches the status under specified election
	 * @author <NAME>
	 */
	public Validator selectCandidatesOfElection(int electionIdKey, Status candidateStatus)
	{
		Validator validator = new Validator();
		ArrayList<CandidateDto> candidates = new ArrayList<CandidateDto>();
		
		PreparedStatement st = null;

		String query = "SELECT candidate_id, candidate_name, election_id, display_order, status "
						+ "	FROM candidate "
						+ " WHERE election_id = ?"
						+ " AND status = ?";

		try {
			st = this.con.prepareStatement(query);
			st.setInt(1, electionIdKey);
			st.setInt(2, candidateStatus.getCode());
			
			ResultSet res = st.executeQuery();

			while (res.next()) {

				int candidateId = res.getInt(1);
				String candidateName = res.getString(2);
				int electionId = res.getInt(3);
				int displayOrder = res.getInt(4);
				int statusId = res.getInt(5);

				CandidateDto candidateDto = new CandidateDto();
				candidateDto.setCandidateId(candidateId);
				candidateDto.setCandidateName(candidateName);
				candidateDto.setElectionId(electionId);
				candidateDto.setDisplayOrder(displayOrder);
				candidateDto.setStatus(statusId);
				
				candidates.add(candidateDto);
				
			} 

		} catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
		}
		
		validator.setObject(candidates);
		return validator;
	}
	
	
	/**
	 * @param name - election name
	 * Add new election to db
	 * @author <NAME>
	 */
	public Validator createNewElection(ElectionDto electionDto){
		PreparedStatement st=null;
		ResultSet rs = null;
		InputValidation iv=new InputValidation();
		Validator val=new Validator();
		
		try{
			val=iv.validateString(electionDto.getElectionName(), "Election name");
			if(val.isVerified()){
				String query = "INSERT INTO election (election_name, status, owner_id) VALUES (?,?,?)";
				int status=ElectionStatus.NEW.getCode();
				st=this.con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
				st.setString(1, electionDto.getElectionName());
				st.setInt(2, status);
				st.setInt(3, electionDto.getOwnerId());

				// update query
				st.executeUpdate();
				// get inserted id
				rs = st.getGeneratedKeys();
				rs.next();
				int id = rs.getInt(1);
								
				val.setStatus("Election added to DB");
				electionDto.setElectionId(id);
				val.setObject(electionDto);
				
				System.out.println(val);
				return val;
			}
			else{
				val.setStatus("Name failed to validate");
				return val;
			}
		}
		catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL error");
			return val;
		}
	}
	
	/**
	 * @param candidateList - candidate array list 
	 * @param election_id - the election to add candidates to
	 * Add candidates to an election
	 * @author <NAME>
	 */
	public Validator addCandidatesToElection(ArrayList<CandidateDto> candidateList, int election_id){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val = new Validator();
		boolean aOK=true;
		try{
			for(int i=0;i<candidateList.size();i++){
				val = iv.validateString(candidateList.get(i).getCandidateName(), "Candidate Name");
				aOK&=val.isVerified();
			}
			if(aOK){
				for(int i=0;i<candidateList.size();i++){
					String query="INSERT INTO candidate (candidate_name, election_id, status) VALUES (?,?,?)";
					st=this.con.prepareStatement(query,Statement.RETURN_GENERATED_KEYS);
					st.setString(1,candidateList.get(i).getCandidateName());
					st.setInt(2, election_id);
					st.setInt(3, Status.ENABLED.getCode());
					int id=st.executeUpdate();
					candidateList.get(i).setCandidateId(id);
				}
				val.setStatus("Candidates added to DB");
				val.setObject(candidateList);
			}
			else{
				val.setStatus("Candidate names failed to validate");
			}
			val.setVerified(aOK);
			return val;
			
		}
		catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setVerified(false);
			val.setStatus("SQL Error");
			return val;
		}
	}
	
	/**
	 * @param candidateDto - candidate object
	 * @author <NAME>
	 */
	public Validator editCandidate(CandidateDto candidateDto){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val = new Validator();
		try{
			val = iv.validateString(candidateDto.getCandidateName(), "Candidate Name");
			boolean valid=true;
			valid&=val.isVerified();
			val=iv.validateInt(candidateDto.getDisplayOrder(), "Display Order");
			valid&=val.isVerified();
			if(valid){
				String query="UPDATE candidate SET (candidate_name, display_order)=(?,?) WHERE candidate_id=?";
				st=this.con.prepareStatement(query);
				st.setString(1, candidateDto.getCandidateName());
				st.setInt(2, candidateDto.getDisplayOrder());
				st.setInt(3,candidateDto.getCandidateId());
				st.execute();
				val.setStatus("Candidate information updated");
				return val;
			}
			else{
				val.setStatus("Candidate information did not validate");
				val.setVerified(false);
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
		
	}
	
	public Validator editCandidateStatus(CandidateDto cand){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val = new Validator();
		try{
			val = iv.validateInt(cand.getStatus(), "Candidate Status");
			if(val.isVerified()){
				String query="UPDATE candidate SET status=? WHERE candidate_id=?";
				st=this.con.prepareStatement(query);
				st.setInt(1, cand.getCandidateId());
				st.execute();
				val.setStatus("Candidate status updated");
				return val;
			}
			else{
				val.setStatus("Status failed to verify");
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	/**
	 * @param electionId - the election to open
	 * Add candidates to an election
	 * @author <NAME>
	 */
	public Validator openElection(int electionId){
		PreparedStatement st=null;
		Validator val=new Validator();
		
		try{
			String query="UPDATE election"
					+ " SET status="+ElectionStatus.NEW.getCode()
					+ " WHERE election_id="+electionId;
			st=this.con.prepareStatement(query);
			st.execute();
			val.setVerified(true);
			val.setStatus("Election opened");
			return val;
		}
		catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	/**
	 * @param electionId - the election to close
	 * Close an election
	 * @author <NAME>
	 */
	public Validator closeElection(int electionId){
		PreparedStatement st=null;
		Validator val=new Validator();
		try{
			String query="UPDATE election"
					+ " SET status="+ ElectionStatus.CLOSED.getCode()
					+ " WHERE election_id="+electionId;
			st=this.con.prepareStatement(query);
			st.execute();
			val.setVerified(true);
			val.setStatus("Election closed");
			return val;
		}
		catch (SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setVerified(false);
			val.setStatus("SQL Error");
			return val;
		}
	}
	
	/**
	 * @param electionId - the election to delete
	 * Delete an election
	 * @author <NAME>
	 */
	public Validator deleteElection(int electionId){
		PreparedStatement st=null;
		Validator val=new Validator();
		try{
			String query="UPDATE election SET status=7 WHERE election_id="+electionId;
			st=this.con.prepareStatement(query);
			st.execute();
			val.setStatus("Election deleted");
			val.setVerified(true);
			return val;
		}
		catch(SQLException ex){
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	/**
	 * @param electionId - the election id to update the status
	 * Delete an election
	 * @author <NAME>
	 */
	public Validator editElectionStatus(int electionId, ElectionStatus electionStatus){
		PreparedStatement st=null;
		Validator val=new Validator();
		try{
			String query="UPDATE election"
					+ " SET status="+electionStatus.getCode()
					+ " WHERE election_id="+electionId;
			st=this.con.prepareStatement(query);
			st.execute();
			val.setStatus("Election status updated");
			val.setVerified(true);
			return val;
		}
		catch(SQLException ex){
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	/**
	 * @param electionDto - the election to edit
	 * Edit an election
	 * @author <NAME>
	 */
	public Validator editElection(ElectionDto electionDto){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val = new Validator();
		try{
			val = iv.validateString(electionDto.getElectionName(), "Election Name");
			if(val.isVerified()){
				String query="UPDATE election SET election_name=? WHERE election_id=?";
				st=this.con.prepareStatement(query);
				st.setString(1, electionDto.getElectionName());
				st.setInt(2,electionDto.getElectionId());
				st.execute();
				val.setStatus("Election updated successfully");
				return val;
			}
			else{
				val.setStatus("New election name did not validate");
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	//Vote
	
	/**
	 * @param voteDto - the vote to submit
	 * Submit a vote
	 * @author <NAME>
	 */
	
	public Validator vote(VoteDto voteDto){
		PreparedStatement st=null;
		InputValidation iv=new InputValidation();
		Validator val=new Validator();
		boolean valid=true;
		val=iv.validateInt(voteDto.getUser_id(), "User ID");
		valid&=val.isVerified();
		val=iv.validateInt(voteDto.getElection_id(), "Election ID");
		valid&=val.isVerified();
		val=iv.validateString(voteDto.getVote_encrypted(), "Encrypted Vote");
		SecurityValidator sec=new SecurityValidator();
		try{
			if(valid && sec.checkSignature(voteDto.getVote_signature(), voteDto.getUser_id()).isVerified()){
				String query="INSERT INTO vote (user_id, election_id, vote_encrypted, vote_signature)"
						+ " VALUES (?,?,?,?)";
				st=this.con.prepareStatement(query);
				st.setInt(1, voteDto.getUser_id());
				st.setInt(2, voteDto.getElection_id());
				st.setString(3, voteDto.getVote_encrypted());
				st.setString(4, voteDto.getVote_signature());
				st.execute();
				val.setStatus("Vote successfully cast");
				val.setVerified(true);
				return val;
			}
			else{
				val.setStatus("Information did not validate");
				val.setVerified(false);
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setStatus("SQL Error");
			val.setVerified(false);
			return val;
		}
	}
	
	public Validator getPubKeyByUserID(int userId){
		PreparedStatement st = null;
		Validator val=new Validator();
		InputValidation iv=new InputValidation();
		val=iv.validateInt(userId, "User ID");
		String query = "SELECT public_key FROM users WHERE user_id = ?";
		try{
			if(val.isVerified()){
				st = this.con.prepareStatement(query);
				st.setInt(1, userId);
				ResultSet res=st.executeQuery();
				if (res.next()) {
					String pubKey = res.getString(1);
					val.setObject(pubKey);
					val.setStatus("Public key retrieved");
					return val;
				}
				else{
					val.setVerified(false);
					val.setStatus("No public key for this user id");
					return val;
				}
			}
			else{
				val.setStatus("User ID did not validate");
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setVerified(false);
			val.setStatus("SQL Error");
			return val;
		}
	}
	
	public Validator selectVotesByElectionId(int election_id){
		Validator val=new Validator();
		InputValidation iv=new InputValidation();
		ArrayList<VoteDto> votes=new ArrayList<VoteDto>();
		val=iv.validateInt(election_id, "Election ID");
		PreparedStatement st=null;
		try{
			if(val.isVerified()){
				String query="SELECT user_id, vote_encrypted, vote_signature, timestamp "
							+ "	FROM vote "
							+ " WHERE election_id = ?";
				st = this.con.prepareStatement(query);
				st.setInt(1, election_id);
				ResultSet res=st.executeQuery();
				while (res.next()) {
					int user_id = res.getInt(1);
					String vote_encrypted = res.getString(2);
					String vote_signature = res.getString(3);
					Timestamp t = res.getTimestamp(4);

					VoteDto vote = new VoteDto();
					vote.setUser_id(user_id);
					vote.setVote_encrypted(vote_encrypted);
					vote.setVote_signature(vote_signature);
					vote.setElection_id(election_id);
					vote.setTimestamp(t);
					
					votes.add(vote);
				}
				val.setStatus("Successfully retrieved votes");
				val.setObject(votes);
				return val;
			}
			else{
				val.setStatus("Election ID failed to validate");
				return val;
			}
		}
		catch(SQLException ex) {
			Logger lgr = Logger.getLogger(DatabaseConnector.class.getName());
			lgr.log(Level.WARNING, ex.getMessage(), ex);
			val.setVerified(false);
			val.setStatus("SQL Error");
			return val;
		}
	}
	
//	public Validator tally(int election_id){
//		Map<CandidateDto, Integer> t= new HashMap<CandidateDto, Integer>();
//		PreparedStatement st=null;
//		Validator val=new Validator();
//		InputValidation iv = new InputValidation();
//		SecurityValidator sec=new SecurityValidator();
//		val=iv.validateInt(election_id, "Election ID");
//		if(val.isVerified()){
//			Validator voteVal=selectVotesByElectionId(election_id);
//			
//			if(voteVal.isVerified()){
//				ArrayList<VoteDto> votes = (ArrayList<VoteDto>)voteVal.getObject();
//				for(int i =0;i<votes.size();i++){
//					String enc=votes.get(i).getVote_encrypted();
//					String sig=votes.get(i).getVote_signature();
//					if(sec.checkSignature(sig, votes.get(i).getUser_id()).isVerified()){
//						int cand_id=Integer.parseInt(sec.decrypt(enc, getTallierSecretKey()), 16);
//						CandidateDto cand=(CandidateDto)selectCandidate(cand_id).getObject();
//						if(t.containsKey(cand)){
//							int total=t.get(cand);
//							total+=1;
//							t.remove(cand);
//							t.put(cand, total);
//						}
//						else{
//							t.put(cand, 1);
//						}
//					}
//					
//				}
//				val.setStatus("Tally computed");
//				val.setObject(t);
//				return val;
//			}
//			else{
//				val.setStatus(voteVal.getStatus());
//				val.setVerified(voteVal.isVerified());
//				return val;
//			}
//		}
//		else{
//			val.setStatus("Election ID failed to verify");
//			return val;
//		}
//	}
}
{'fraction_non_alphanumeric': 0.12630134661084078, 'fraction_numerical': 0.004031345479235035, 'mean_word_length': 3.820797817933856, 'pattern_counts': {'":': 2, '<': 95, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3850801', 'n_tokens_mistral': 26358, 'n_tokens_neox': 22389, 'n_words': 4772}