summaryrefslogtreecommitdiff
path: root/src/main/java/design/model/course_search/CurrentSearchQuery.java
blob: b7f06862779cbffb2518061a6152c0f1e61b03c7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package design.model.course_search;

import design.persistence.MasterDatabase;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/*
 * Represents the state of our current search.
 */
public class CurrentSearchQuery {

    // initialize our search with the master db data
    MasterDatabase db = MasterDatabase.instance();
    private CourseList query = db.getCourseList();
    private final List<CourseSorter> filters = new ArrayList<>();

    // reset the query
    public void reset() {
        query = db.getCourseList();
    }

    // add a new filter
    public void addFilter(CourseSorter filter) {
        filters.add(filter);
    }

    // clear the filters
    public void clearFilters() {
        filters.clear();
    }

    // print out the filters we're currently using and the order
    public String printFilters() {
        StringBuilder filterResult = new StringBuilder();

        // no filters? let the user know.
        if (filters.isEmpty()) {
            return "nothing";
        }

        for (CourseSorter f : filters) {
            filterResult.append(f.toString()).append(" --> ");
        }

        // remove last arrow and add padding
        filterResult = new StringBuilder(filterResult.substring(0, filterResult.length() - 5));
        filterResult.append("\n");

        return filterResult.toString();
    }

    // get all the filters
    public List<CourseSorter> getFilters() {
        return filters;
    }

    // get our current query.
    public CourseList getQueryResult() {
        return query;
    }

    public void search(String searchQuery) {
        // only grab courses which fit our search
        List<ICourse> courses = db.getCourseList().getCourses().stream()
                .filter(s -> s.toString().toLowerCase().contains(searchQuery.toLowerCase()))
                .collect(Collectors.toList());

        // and now, we filter it!
        CourseList filtered = applyFilters(filters, courses);
        query.setCourses(filtered.getCourses());
    }

    // to apply our filters we need to traverse the tree and make new grouping as we go. 
    public CourseList applyFilters(List<CourseSorter> filters, List<ICourse> coursesToFilter) {
        CourseList root = new CourseList();
        root.setCourses(applyFiltersRecursive(coursesToFilter, filters, 0));
        return root;
    }

    // the actual recursive part. Level is how many filters deep we are.
    private List<ICourse> applyFiltersRecursive(List<ICourse> courses, List<CourseSorter> filters, int level) {
        // base case. we have gone past all filters or theres only one course in this list. already sorted!
        if (level >= filters.size() || courses.size() <= 1) {
            return courses;
        }

        // grab out current sorting strategy for this level, and sort the courselist.
        CourseSorter sorter = filters.get(level);
        sorter.sortCourses(courses);

        // the resulting sorted list, with new groupings
        List<ICourse> result = new ArrayList<>();

        // courses with an equal value.
        List<ICourse> currentGroup = new ArrayList<>();

        ICourse prev = null;

        // run through the courses, if
        for (ICourse c : courses) {
            /* always add the first course to a new group. when iterating through courses, if we have to values that are equal, we need to add them into a group together.
             * think about it this way. If we have [ 1, 2, 2, 2, 3, 4 ]. 1 is first, so its in it's own group. 2 /= 1, so 2 gets its own group.
             * now do 2 again. we add it to the existing group 2. Same with the next 2. Now 3. 3 /= 2, so we put it in it's own group.
             */
            if (prev == null || !sorter.isEqual(prev, c)) {
                // already a course in that group? we now have two equal values and so 
                if (!currentGroup.isEmpty()) {
                    result.add(makeGroup(currentGroup, filters, level));
                    currentGroup = new ArrayList<>();
                }
            }

            currentGroup.add(c);
            prev = c;
        }

        // handle the last group.
        if (!currentGroup.isEmpty()) {
            result.add(makeGroup(currentGroup, filters, level));
        }

        return result;
    }

    // make a CourseList group, a sublist of a group, and filter it. 
    private ICourse makeGroup(List<ICourse> group, List<CourseSorter> filters, int level) {
        // base case, group only has one course in it (already sorted)
        if (group.size() == 1) return group.getFirst();

        // group has more than 1 course in it, it needs to be sorted more if possible.
        CourseList subList = new CourseList();
        subList.setCourses(applyFiltersRecursive(group, filters, level + 1));
        return subList;
    }
}