<commit_before>package ca.corefacility.bioinformatics.irida.repositories.specification;

import java.util.ArrayList;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.data.jpa.domain.Specification;

import ca.corefacility.bioinformatics.irida.model.project.Project;

/**
 * Specification for searching project properties
 * 
 *
 */
public class ProjectSpecification {
	/**
	 * Search for a project by name
	 * 
	 * @param name
	 *            the name to use in the search.
	 * @return a {@link Specification} on project name.
	 */
	public static Specification<Project> searchProjectName(String name) {
		return new Specification<Project>() {
			@Override
			public Predicate toPredicate(Root<Project> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				return cb.like(root.get("name"), "%" + name + "%");
			}

		};
	}

	/**
	 * Exclude the given projects from the results
	 * 
	 * @param projects
	 *            The projects to exclude
	 * @return A specification instructing to exclude the given projects
	 */
	public static Specification<Project> excludeProject(Project... projects) {
		return new Specification<Project>() {
			@Override
			public Predicate toPredicate(Root<Project> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

				ArrayList<Predicate> predicates = new ArrayList<>();
				for (Project p : projects) {
					predicates.add(cb.notEqual(root, p));
				}

				return cb.and(predicates.toArray(new Predicate[predicates.size()]));
			}
		};
	}

	/**
	 * Search for projects based on submitted criteria
	 *
	 * @param searchMap
	 * 		{@link Map} The keys correspond to {@link Project} attributes to filter by.
	 *
	 * @return A {@link Specification}
	 */
	public static Specification<Project> filterAllProjectsByProjectAttributes(Map<String, String> searchMap) {
		return (root, query, cb) -> {
			ArrayList<Predicate> predicates = new ArrayList<>();

			if (searchMap.containsKey("name")) {
				predicates.add(cb.like(root.get("name"), "%" + searchMap.get("name") + "%"));
			}
			if (searchMap.containsKey("organism")) {
				predicates.add(cb.like(root.get("organism"), "%" + searchMap.get("organism") + "%"));
			}

			return cb.and(predicates.toArray(new Predicate[predicates.size()]));
		};
	}

	/**
	 * Filter all {@link Project}s by a general search term again project attributes.
	 *  This search {@link Specification} is for searching {@link Project}'s via any attribute
	 *  (currently only id, name, and organism).
	 *
	 * @param term
	 * 		{@link String} The search query.
	 *
	 * @return {@link Specification}
	 */
	public static Specification<Project> filterAllProjectsAllFields(String term) {
		return (root, query, cb) -> {
			ArrayList<Predicate> predicates = new ArrayList<>();

			// Since the project id is a long, we first check to ensure that it is a number being searched
			// If it is, then to get the search to work within a long, we need to cast that id as a string
			// and then proceed with the search.
			if (term.matches("\\d*")) {
				predicates.add(cb.like(root.get("id").as(String.class), "%" + term + "%"));
			}
			predicates.add(cb.like(root.get("name"), "%" + term + "%"));
			predicates.add(cb.like(root.get("organism"), "%" + term + "%"));

			return cb.or(predicates.toArray(new Predicate[predicates.size()]));
		};
	}

	public static Specification<Project> filterProjectByAnythingAndEverything(Map<String, String> filterMap, String term) {
		return (root, query, cb) -> {
			Predicate filteredPredicatesList = getFilteredPredicates(cb, root, filterMap);
			Predicate searchPredicatesList = getSearchPredicates(cb, root, term);

			// Filter gets first priority
			
			return cb.and(new Predicate[] {filteredPredicatesList,searchPredicatesList});
		};
	}

	private static Predicate getFilteredPredicates(CriteriaBuilder cb, Root<Project> root, Map<String, String> filterMap) {
		ArrayList<Predicate> predicates = new ArrayList<>();

		if (filterMap.containsKey("name")) {
			predicates.add(cb.like(root.get("name"), "%" + filterMap.get("name") + "%"));
		}
		if (filterMap.containsKey("organism")) {
			predicates.add(cb.like(root.get("organism"), "%" + filterMap.get("organism") + "%"));
		}
		return cb.and(predicates.toArray(new Predicate[predicates.size()]));
	}

	private static Predicate getSearchPredicates(CriteriaBuilder cb, Root<Project> root, String term) {
		ArrayList<Predicate> predicates = new ArrayList<>();

		// Since the project id is a long, we first check to ensure that it is a number being searched
		// If it is, then to get the search to work within a long, we need to cast that id as a string<commit_msg>Updated specifcation documentation and renamed method.<commit_after>package ca.corefacility.bioinformatics.irida.repositories.specification;

import java.util.ArrayList;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.data.jpa.domain.Specification;

import ca.corefacility.bioinformatics.irida.model.project.Project;
import ca.corefacility.bioinformatics.irida.model.user.User;

/**
 * Specification for searching project properties
 * 
 *
 */
public class ProjectSpecification {
	/**
	 * Search for a project by name
	 * 
	 * @param name
	 *            the name to use in the search.
	 * @return a {@link Specification} on project name.
	 */
	public static Specification<Project> searchProjectName(String name) {
		return new Specification<Project>() {
			@Override
			public Predicate toPredicate(Root<Project> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				return cb.like(root.get("name"), "%" + name + "%");
			}

		};
	}

	/**
	 * Exclude the given projects from the results
	 * 
	 * @param projects
	 *            The projects to exclude
	 * @return A specification instructing to exclude the given projects
	 */
	public static Specification<Project> excludeProject(Project... projects) {
		return new Specification<Project>() {
			@Override
			public Predicate toPredicate(Root<Project> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

				ArrayList<Predicate> predicates = new ArrayList<>();
				for (Project p : projects) {
					predicates.add(cb.notEqual(root, p));
				}

				return cb.and(predicates.toArray(new Predicate[predicates.size()]));
			}
		};
	}

	/**
	 * Search through {@link Project}s for a {@link User} based on specific attributes or through a generalized search
	 * string.
	 *
	 * @param filterMap
	 * 		{@link Map} of {@link Project} attributes to search with the searc term.
	 * @param term
	 * 		{@link String} A general search term to search the {@link Project} attributes.
	 *
	 * @return {@link Specification} for the search.
	 */
	public static Specification<Project> filterProjectsByAdvancedFiltersAndSearch(Map<String, String> filterMap, String term) {
		return (root, query, cb) -> {
			Predicate filteredPredicatesList = getFilteredPredicates(cb, root, filterMap);
			Predicate searchPredicatesList = getSearchPredicates(cb, root, term);

			// Filter gets first priority
			
			return cb.and(new Predicate[] {filteredPredicatesList,searchPredicatesList});
		};
	}

	/**
	 * Create a {@link Predicate} based on a {@link Map} of {@link Project} attributes with their corresponding search
	 * string..
	 *
	 * @param cb
	 * 		{@link CriteriaBuilder} for a {@link Specification}
	 * @param root
	 * 		{@link Root}
	 * @param filterMap
	 * 		{@link Map} of {@link Project} attributes to search with their corresponding search term.
	 *
	 * @return {@link Predicate}
	 */
	private static Predicate getFilteredPredicates(CriteriaBuilder cb, Root<Project> root, Map<String, String> filterMap) {
		ArrayList<Predicate> predicates = new ArrayList<>();

		if (filterMap.containsKey("name")) {
			predicates.add(cb.like(root.get("name"), "%" + filterMap.get("name") + "%"));
		}
		if (filterMap.containsKey("organism")) {
			predicates.add(cb.like(root.get("organism"), "%" + filterMap.get("organism") + "%"));
		}
		return cb.and(predicates.toArray(new Predicate[predicates.size()]));
	}

	/**
	 * Create a {@link Predicate} to search 'all' {@link Project} attribute for one general search {@link String}
	 *
	 * @param cb
	 * 		{@link CriteriaBuilder} for a {@link Specification}
	 * @param root
	 * 		{@link Root}
	 * @param term
	 * 		{@link String} term to search the {@link Project} attributes for.
	 *
	 * @return {@link Predicate}
	 */
	private static Predicate getSearchPredicates(CriteriaBuilder cb, Root<Project> root, String term) {
		ArrayList<Predicate> predicates = new ArrayList<>();

		// Since the project id is a long, we first check to ensure that it is a number being searched
		// If it is, then to get the search to work within a long, we need to cast that id as a string
{'fraction_non_alphanumeric': 0.1269982238010657, 'fraction_numerical': 0.0, 'mean_word_length': 4.133333333333334, 'pattern_counts': {'":': 0, '<': 48, '<?xml version=': 0, '>': 52, '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': '539821', 'n_tokens_mistral': 2865, 'n_tokens_neox': 2574, 'n_words': 768}