// Path: eva-lib/src/main/java/uk/ac/ebi/eva/lib/extension/GenericSpecifications.java
// public class GenericSpecifications<T> {
// 
//     public static <T> Specification<T> isEqual(String attributeName, Object object) {
//         return new Specification<T>(){
// 
//             @Override
//             public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//                 return cb.equal(root.get(attributeName),object);
//             }
//         };
//     }
// 
//     public static <T> Specification<T> in(String attributeName, Object ... objects) {
//         return new Specification<T>() {
//             @Override
//             public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//                 return root.get(attributeName).in(objects);
//             }
//         };
//     }
// 
//     public static <T> Specification<T> like(String attributeName, String pattern) {
//         return new Specification<T>() {
//             @Override
//             public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//                 return criteriaBuilder.like(root.get(attributeName), pattern);
//             }
//         };
//     }
// 
// 
//     public static <T> Specification<T> ilike(String attributeName, String pattern) {
//         return new Specification<T>() {
//             @Override
//             public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//                 return criteriaBuilder.like(criteriaBuilder.lower(root.get(attributeName)),
//                                             criteriaBuilder.lower(criteriaBuilder.literal(pattern)));
//             }
//         };
//     }
// }
// 
// Path: eva-lib/src/main/java/uk/ac/ebi/eva/lib/repositories/EvaStudyBrowserRepository.java
// public interface EvaStudyBrowserRepository extends JpaRepository<EvaStudyBrowser, String>, ExtendedJpaRepositoryFunctions<EvaStudyBrowser, String>, JpaSpecificationExecutor<EvaStudyBrowser>{
// 
//     public static final String COMMON_NAME = "commonName";
//     public static final String SCIENTIFIC_NAME = "scientificName";
//     public static final String EXPERIMENT_TYPE = "experimentType";
// }
// 
// Path: eva-lib/src/main/java/uk/ac/ebi/eva/lib/utils/QueryOptions.java
// public class QueryOptions extends ObjectMap {
// 
// 
//     public QueryOptions() {
// 
//     }
// 
//     public QueryOptions(int size) {
//         super(size);
//     }
// 
//     public QueryOptions(final String key, final Object value) {
//         super(key, value);
//     }
// 
//     public QueryOptions(final Map<String, Object> inputOptions) {
//         super(inputOptions);
//     }
// 
//     public QueryOptions(final Map<String, ?> inputOptions, boolean pickFirstValue) {
//         if (pickFirstValue) {
//             for (Map.Entry<String, ?> option : inputOptions.entrySet()) {
//                 if (option.getValue() instanceof List) {
//                     this.put(option.getKey(), ((List) option.getValue()).get(0));
//                 }
//             }
//         } else {
//             this.putAll(inputOptions);
//         }
//     }
// 
//     /**
//      * This method safely add new options. If the key already exists it does not overwrite the current value.
//      * You can use put for overwritten the value.
//      *
//      * @param key
//      * @param value
//      * @return null if the key was not present, or the existing object if the key exists.
//      */
//     public Object add(String key, Object value) {
//         if (!this.containsKey(key)) {
//             this.put(key, value);
//             return null;
//         }
//         return this.get(key);
//     }
// 
//     /**
//      * This method safely add a new Object to an exiting option which type is List.
//      *
//      * @param key
//      * @param value
//      * @return the list with the new Object inserted.
//      */
//     public Object addToListOption(String key, Object value) {
//         if (key != null && !key.equals("")) {
//             if (this.containsKey(key) && this.get(key) != null) {
//                 if (!(this.get(key) instanceof List)) { //If was not a list, getAsList returns an Unmodifiable List.
//                     // Create new modifiable List with the content, and replace.
//                     this.put(key, new ArrayList<>(this.getAsList(key)));
//                 }
//                 this.getList(key).add(value);
//             } else {
//                 List<Object> list = new ArrayList<>();  //New List instead of "Arrays.asList" or "Collections.singletonList" to avoid unmodifiable list.
//                 list.add(value);
//                 this.put(key, list);
//             }
//             return this.getList(key);
//         }
//         return null;
//     }
// }


import org.springframework.data.jpa.domain.Specification;
import uk.ac.ebi.eva.commons.core.models.StudyType;
import uk.ac.ebi.eva.lib.extension.GenericSpecifications;
import uk.ac.ebi.eva.lib.repositories.EvaStudyBrowserRepository;
import uk.ac.ebi.eva.lib.utils.QueryOptions;
import uk.ac.ebi.eva.lib.utils.QueryOptionsConstants;
import static org.springframework.data.jpa.domain.Specification.where;
                return StudyType.COLLECTION;
            case "Control Set":
            case "Control-Set":
                return StudyType.CONTROL;
            case "Case Control":
            case "Case-Control":
                return StudyType.CASE_CONTROL;
            case "Case Set":
            case "Case-Set":
                return StudyType.CASE;
            case "Tumor vs. Matched-Normal":
                return StudyType.PAIRED_TUMOR;
            case "Aggregate":
                return StudyType.AGGREGATE;
            case "Somatic":
                return StudyType.SOMATIC;
            default:
                throw new IllegalArgumentException("Study type " + studyType + " is not valid");
        }
    }

    public static Specification getSpeciesAndTypeFilters(QueryOptions queryOptions) {
        if (!queryOptions.containsKey(QueryOptionsConstants.SPECIES) && !queryOptions.containsKey(QueryOptionsConstants.TYPE)) {
            return null;
        }

        Specification speciesSpecifications = null;
        if (queryOptions.containsKey(QueryOptionsConstants.SPECIES)) {
            Object[] species = queryOptions.getAsStringList(QueryOptionsConstants.SPECIES).toArray(new Object[]{});
            speciesSpecifications = where(GenericSpecifications.in(EvaStudyBrowserRepository.COMMON_NAME, species))
// Path: eva-lib/src/main/java/uk/ac/ebi/eva/lib/extension/GenericSpecifications.java
// public class GenericSpecifications<T> {
// 
//     public static <T> Specification<T> isEqual(String attributeName, Object object) {
//         return new Specification<T>(){
// 
//             @Override
//             public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//                 return cb.equal(root.get(attributeName),object);
//             }
//         };
//     }
// 
//     public static <T> Specification<T> in(String attributeName, Object ... objects) {
//         return new Specification<T>() {
//             @Override
//             public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//                 return root.get(attributeName).in(objects);
//             }
//         };
//     }
// 
//     public static <T> Specification<T> like(String attributeName, String pattern) {
//         return new Specification<T>() {
//             @Override
//             public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//                 return criteriaBuilder.like(root.get(attributeName), pattern);
//             }
//         };
//     }
// 
// 
//     public static <T> Specification<T> ilike(String attributeName, String pattern) {
//         return new Specification<T>() {
//             @Override
//             public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//                 return criteriaBuilder.like(criteriaBuilder.lower(root.get(attributeName)),
//                                             criteriaBuilder.lower(criteriaBuilder.literal(pattern)));
//             }
//         };
//     }
// }
// 
// Path: eva-lib/src/main/java/uk/ac/ebi/eva/lib/repositories/EvaStudyBrowserRepository.java
// public interface EvaStudyBrowserRepository extends JpaRepository<EvaStudyBrowser, String>, ExtendedJpaRepositoryFunctions<EvaStudyBrowser, String>, JpaSpecificationExecutor<EvaStudyBrowser>{
// 
//     public static final String COMMON_NAME = "commonName";
//     public static final String SCIENTIFIC_NAME = "scientificName";
//     public static final String EXPERIMENT_TYPE = "experimentType";
// }
// 
// Path: eva-lib/src/main/java/uk/ac/ebi/eva/lib/utils/QueryOptions.java
// public class QueryOptions extends ObjectMap {
// 
// 
//     public QueryOptions() {
// 
//     }
// 
//     public QueryOptions(int size) {
//         super(size);
//     }
// 
//     public QueryOptions(final String key, final Object value) {
//         super(key, value);
//     }
// 
//     public QueryOptions(final Map<String, Object> inputOptions) {
//         super(inputOptions);
//     }
// 
//     public QueryOptions(final Map<String, ?> inputOptions, boolean pickFirstValue) {
//         if (pickFirstValue) {
//             for (Map.Entry<String, ?> option : inputOptions.entrySet()) {
//                 if (option.getValue() instanceof List) {
//                     this.put(option.getKey(), ((List) option.getValue()).get(0));
//                 }
//             }
//         } else {
//             this.putAll(inputOptions);
//         }
//     }
// 
//     /**
//      * This method safely add new options. If the key already exists it does not overwrite the current value.
//      * You can use put for overwritten the value.
//      *
//      * @param key
//      * @param value
//      * @return null if the key was not present, or the existing object if the key exists.
//      */
//     public Object add(String key, Object value) {
//         if (!this.containsKey(key)) {
//             this.put(key, value);
//             return null;
//         }
//         return this.get(key);
//     }
// 
//     /**
//      * This method safely add a new Object to an exiting option which type is List.
//      *
//      * @param key
//      * @param value
//      * @return the list with the new Object inserted.
//      */
//     public Object addToListOption(String key, Object value) {
//         if (key != null && !key.equals("")) {
//             if (this.containsKey(key) && this.get(key) != null) {
//                 if (!(this.get(key) instanceof List)) { //If was not a list, getAsList returns an Unmodifiable List.
//                     // Create new modifiable List with the content, and replace.
//                     this.put(key, new ArrayList<>(this.getAsList(key)));
//                 }
//                 this.getList(key).add(value);
//             } else {
//                 List<Object> list = new ArrayList<>();  //New List instead of "Arrays.asList" or "Collections.singletonList" to avoid unmodifiable list.
//                 list.add(value);
//                 this.put(key, list);
//             }
//             return this.getList(key);
//         }
//         return null;
//     }
// }


// Path: eva-lib/src/main/java/uk/ac/ebi/eva/lib/eva_utils/EvaproDbUtils.java
import org.springframework.data.jpa.domain.Specification;
import uk.ac.ebi.eva.commons.core.models.StudyType;
import uk.ac.ebi.eva.lib.extension.GenericSpecifications;
import uk.ac.ebi.eva.lib.repositories.EvaStudyBrowserRepository;
import uk.ac.ebi.eva.lib.utils.QueryOptions;
import uk.ac.ebi.eva.lib.utils.QueryOptionsConstants;
import static org.springframework.data.jpa.domain.Specification.where;

                return StudyType.COLLECTION;
            case "Control Set":
            case "Control-Set":
                return StudyType.CONTROL;
            case "Case Control":
            case "Case-Control":
                return StudyType.CASE_CONTROL;
            case "Case Set":
            case "Case-Set":
                return StudyType.CASE;
            case "Tumor vs. Matched-Normal":
                return StudyType.PAIRED_TUMOR;
            case "Aggregate":
                return StudyType.AGGREGATE;
            case "Somatic":
                return StudyType.SOMATIC;
            default:
                throw new IllegalArgumentException("Study type " + studyType + " is not valid");
        }
    }

    public static Specification getSpeciesAndTypeFilters(QueryOptions queryOptions) {
        if (!queryOptions.containsKey(QueryOptionsConstants.SPECIES) && !queryOptions.containsKey(QueryOptionsConstants.TYPE)) {
            return null;
        }

        Specification speciesSpecifications = null;
        if (queryOptions.containsKey(QueryOptionsConstants.SPECIES)) {
            Object[] species = queryOptions.getAsStringList(QueryOptionsConstants.SPECIES).toArray(new Object[]{});
            speciesSpecifications = where(GenericSpecifications.in(EvaStudyBrowserRepository.COMMON_NAME, species))
                    .or(GenericSpecifications.in(EvaStudyBrowserRepository.SCIENTIFIC_NAME, species));