Skip to content

Commit e5e5c92

Browse files
committed
Add case-insensitive configuration wrappers for file handling
1 parent 5ff6ea8 commit e5e5c92

File tree

3 files changed

+1255
-166
lines changed

3 files changed

+1255
-166
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
package com.bencodez.simpleapi.file;
2+
3+
import org.bukkit.configuration.ConfigurationSection;
4+
import org.bukkit.configuration.file.FileConfiguration;
5+
6+
import java.util.Collections;
7+
import java.util.List;
8+
import java.util.Set;
9+
10+
/**
11+
* Wrapper that makes all file configuration lookups case-insensitive.
12+
*/
13+
public class CaseInsensitiveFileConfiguration {
14+
15+
private final FileConfiguration delegate;
16+
17+
public CaseInsensitiveFileConfiguration(FileConfiguration delegate) {
18+
if (delegate == null) {
19+
throw new IllegalArgumentException("delegate cannot be null");
20+
}
21+
this.delegate = delegate;
22+
}
23+
24+
public FileConfiguration getDelegate() {
25+
return delegate;
26+
}
27+
28+
// --------------------------------------------------------
29+
// Internal helpers
30+
// --------------------------------------------------------
31+
32+
private static String findRealKey(ConfigurationSection section, String key) {
33+
if (section == null || key == null) {
34+
return null;
35+
}
36+
for (String k : section.getKeys(false)) {
37+
if (k.equalsIgnoreCase(key)) {
38+
return k;
39+
}
40+
}
41+
return null;
42+
}
43+
44+
private static class ResolvedPath {
45+
final ConfigurationSection section;
46+
final String key;
47+
48+
ResolvedPath(ConfigurationSection section, String key) {
49+
this.section = section;
50+
this.key = key;
51+
}
52+
}
53+
54+
/** Resolve nested path ignoring case for each segment */
55+
private ResolvedPath resolvePath(String path) {
56+
if (path == null || path.isEmpty()) {
57+
return null;
58+
}
59+
60+
String[] parts = path.split("\\.");
61+
ConfigurationSection current = delegate;
62+
63+
if (parts.length == 1) {
64+
String real = findRealKey(current, parts[0]);
65+
if (real == null)
66+
return null;
67+
return new ResolvedPath(current, real);
68+
}
69+
70+
// walk intermediate sections
71+
for (int i = 0; i < parts.length - 1; i++) {
72+
String part = parts[i];
73+
String realKey = findRealKey(current, part);
74+
if (realKey == null)
75+
return null;
76+
77+
current = current.getConfigurationSection(realKey);
78+
if (current == null)
79+
return null;
80+
}
81+
82+
// last key
83+
String last = parts[parts.length - 1];
84+
String realLast = findRealKey(current, last);
85+
if (realLast == null)
86+
return null;
87+
88+
return new ResolvedPath(current, realLast);
89+
}
90+
91+
// --------------------------------------------------------
92+
// Generic accessors
93+
// --------------------------------------------------------
94+
95+
public Object get(String path) {
96+
ResolvedPath rp = resolvePath(path);
97+
return rp == null ? null : rp.section.get(rp.key);
98+
}
99+
100+
public Object get(String path, Object def) {
101+
Object val = get(path);
102+
return val != null ? val : def;
103+
}
104+
105+
public boolean contains(String path) {
106+
return resolvePath(path) != null;
107+
}
108+
109+
public boolean isSet(String path) {
110+
return contains(path);
111+
}
112+
113+
// --------------------------------------------------------
114+
// Typed shortcuts
115+
// --------------------------------------------------------
116+
117+
public String getString(String path) {
118+
ResolvedPath rp = resolvePath(path);
119+
return rp == null ? null : rp.section.getString(rp.key);
120+
}
121+
122+
public String getString(String path, String def) {
123+
String v = getString(path);
124+
return v != null ? v : def;
125+
}
126+
127+
public int getInt(String path) {
128+
ResolvedPath rp = resolvePath(path);
129+
return rp == null ? 0 : rp.section.getInt(rp.key);
130+
}
131+
132+
public int getInt(String path, int def) {
133+
ResolvedPath rp = resolvePath(path);
134+
return rp == null ? def : rp.section.getInt(rp.key, def);
135+
}
136+
137+
public long getLong(String path) {
138+
ResolvedPath rp = resolvePath(path);
139+
return rp == null ? 0L : rp.section.getLong(rp.key);
140+
}
141+
142+
public long getLong(String path, long def) {
143+
ResolvedPath rp = resolvePath(path);
144+
return rp == null ? def : rp.section.getLong(rp.key, def);
145+
}
146+
147+
public double getDouble(String path) {
148+
ResolvedPath rp = resolvePath(path);
149+
return rp == null ? 0.0 : rp.section.getDouble(rp.key);
150+
}
151+
152+
public double getDouble(String path, double def) {
153+
ResolvedPath rp = resolvePath(path);
154+
return rp == null ? def : rp.section.getDouble(rp.key, def);
155+
}
156+
157+
public boolean getBoolean(String path) {
158+
ResolvedPath rp = resolvePath(path);
159+
return rp != null && rp.section.getBoolean(rp.key);
160+
}
161+
162+
public boolean getBoolean(String path, boolean def) {
163+
ResolvedPath rp = resolvePath(path);
164+
return rp == null ? def : rp.section.getBoolean(rp.key, def);
165+
}
166+
167+
@SuppressWarnings("unchecked")
168+
public List<?> getList(String path) {
169+
ResolvedPath rp = resolvePath(path);
170+
if (rp == null)
171+
return null;
172+
Object v = rp.section.get(rp.key);
173+
return v instanceof List<?> ? (List<?>) v : null;
174+
}
175+
176+
public List<String> getStringList(String path) {
177+
ResolvedPath rp = resolvePath(path);
178+
return rp == null ? Collections.emptyList() : rp.section.getStringList(rp.key);
179+
}
180+
181+
// --------------------------------------------------------
182+
// Section handling
183+
// --------------------------------------------------------
184+
185+
public CaseInsensitiveSectionWrapper getSection(String path) {
186+
if (path == null || path.isEmpty()) {
187+
return new CaseInsensitiveSectionWrapper(delegate);
188+
}
189+
190+
String[] parts = path.split("\\.");
191+
ConfigurationSection current = delegate;
192+
193+
for (String part : parts) {
194+
String realKey = findRealKey(current, part);
195+
if (realKey == null) {
196+
return null;
197+
}
198+
current = current.getConfigurationSection(realKey);
199+
if (current == null) {
200+
return null;
201+
}
202+
}
203+
204+
return new CaseInsensitiveSectionWrapper(current);
205+
}
206+
207+
public Set<String> getKeys(boolean deep) {
208+
return delegate.getKeys(deep);
209+
}
210+
211+
// --------------------------------------------------------
212+
// Nested class for wrapping child sections
213+
// --------------------------------------------------------
214+
public static class CaseInsensitiveSectionWrapper extends CaseInsensitiveFileConfiguration {
215+
216+
public CaseInsensitiveSectionWrapper(ConfigurationSection section) {
217+
super((FileConfiguration) section); // safe because Bukkit internally uses FileConfiguration for all
218+
// top-levels
219+
}
220+
}
221+
}

0 commit comments

Comments
 (0)