summaryrefslogtreecommitdiff
path: root/src/main/java/sevenUnitsGUI/FilterComparator.java
blob: ff942fb601e017075cc91a4fc108ed057706f51c (plain)
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
/**
 * Copyright (C) 2018, 2022, 2024, 2025 Adrien Hopkins
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
package sevenUnitsGUI;

import java.util.Comparator;
import java.util.Objects;

/**
 * A comparator that compares strings using a filter.
 *
 * @param <T> type of element being compared
 *
 * @author Adrien Hopkins
 * @since 2019-01-15
 * @since v0.1.0
 */
final class FilterComparator<T> implements Comparator<T> {
	/**
	 * The filter that the comparator is filtered by.
	 *
	 * @since 2019-01-15
	 * @since v0.1.0
	 */
	private final String filter;
	/**
	 * The comparator to use if the arguments are otherwise equal.
	 *
	 * @since 2019-01-15
	 * @since v0.1.0
	 */
	private final Comparator<T> comparator;
	/**
	 * Whether or not the comparison is case-sensitive.
	 *
	 * @since 2019-04-14
	 * @since v0.2.0
	 */
	private final boolean caseSensitive;

	/**
	 * Creates the {@code FilterComparator}.
	 *
	 * @param filter
	 * @since 2019-01-15
	 * @since v0.1.0
	 */
	public FilterComparator(final String filter) {
		this(filter, null);
	}

	/**
	 * Creates the {@code FilterComparator}.
	 *
	 * @param filter     string to filter by
	 * @param comparator comparator to fall back to if all else fails, null is
	 *                   compareTo.
	 * @throws NullPointerException if filter is null
	 * @since 2019-01-15
	 * @since v0.1.0
	 */
	public FilterComparator(final String filter,
			final Comparator<T> comparator) {
		this(filter, comparator, false);
	}

	/**
	 * Creates the {@code FilterComparator}.
	 *
	 * @param filter        string to filter by
	 * @param comparator    comparator to fall back to if all else fails, null is
	 *                      compareTo.
	 * @param caseSensitive whether or not the comparator is case-sensitive
	 * @throws NullPointerException if filter is null
	 * @since 2019-04-14
	 * @since v0.2.0
	 */
	public FilterComparator(final String filter, final Comparator<T> comparator,
			final boolean caseSensitive) {
		Objects.requireNonNull(filter, "filter must not be null.");
		this.filter = caseSensitive ? filter : filter.toLowerCase();
		this.comparator = comparator;
		this.caseSensitive = caseSensitive;
	}

	/**
	 * Compares two objects according to whether or not they match a filter.
	 * Objects whose string representation starts with the filter's text go
	 * first, then those that contain it but don't start with it, then those that
	 * don't contain it. Objects in the same order here are sorted by their
	 * string representation's compareTo or the provided comparator.
	 */
	@Override
	public int compare(final T arg0, final T arg1) {
		// if this is case insensitive, make them lowercase
		final String str0, str1;
		if (this.caseSensitive) {
			str0 = arg0.toString();
			str1 = arg1.toString();
		} else {
			str0 = arg0.toString().toLowerCase();
			str1 = arg1.toString().toLowerCase();
		}

		// elements that start with the filter always go first
		if (str0.startsWith(this.filter) && !str1.startsWith(this.filter))
			return -1;
		if (!str0.startsWith(this.filter) && str1.startsWith(this.filter))
			return 1;

		// elements that contain the filter but don't start with them go next
		if (str0.contains(this.filter) && !str1.contains(this.filter))
			return -1;
		if (!str0.contains(this.filter) && !str1.contains(this.filter))
			return 1;

		// other elements go last
		if (this.comparator == null)
			return str0.compareTo(str1);
		return this.comparator.compare(arg0, arg1);
	}
}