001package net.minecraftforge.common; 002 003import static net.minecraftforge.common.Configuration.NEW_LINE; 004import static net.minecraftforge.common.Configuration.allowedProperties; 005 006import java.io.BufferedWriter; 007import java.io.IOException; 008import java.util.ArrayList; 009import java.util.Collection; 010import java.util.Map; 011import java.util.Set; 012import java.util.TreeMap; 013import com.google.common.collect.ImmutableMap; 014import com.google.common.collect.ImmutableSet; 015import com.google.common.base.Splitter; 016 017public class ConfigCategory implements Map<String, Property> 018{ 019 private String name; 020 private String comment; 021 private ArrayList<ConfigCategory> children = new ArrayList<ConfigCategory>(); 022 private Map<String, Property> properties = new TreeMap<String, Property>(); 023 public final ConfigCategory parent; 024 private boolean changed = false; 025 026 public ConfigCategory(String name) 027 { 028 this(name, null); 029 } 030 031 public ConfigCategory(String name, ConfigCategory parent) 032 { 033 this.name = name; 034 this.parent = parent; 035 if (parent != null) 036 { 037 parent.children.add(this); 038 } 039 } 040 041 public boolean equals(Object obj) 042 { 043 if (obj instanceof ConfigCategory) 044 { 045 ConfigCategory cat = (ConfigCategory)obj; 046 return name.equals(cat.name) && children.equals(cat.children); 047 } 048 049 return false; 050 } 051 052 public String getQualifiedName() 053 { 054 return getQualifiedName(name, parent); 055 } 056 057 public static String getQualifiedName(String name, ConfigCategory parent) 058 { 059 return (parent == null ? name : parent.getQualifiedName() + Configuration.CATEGORY_SPLITTER + name); 060 } 061 062 public ConfigCategory getFirstParent() 063 { 064 return (parent == null ? this : parent.getFirstParent()); 065 } 066 067 public boolean isChild() 068 { 069 return parent != null; 070 } 071 072 public Map<String, Property> getValues() 073 { 074 return ImmutableMap.copyOf(properties); 075 } 076 077 public void setComment(String comment) 078 { 079 this.comment = comment; 080 } 081 082 public boolean containsKey(String key) 083 { 084 return properties.containsKey(key); 085 } 086 087 public Property get(String key) 088 { 089 return properties.get(key); 090 } 091 092 private void write(BufferedWriter out, String... data) throws IOException 093 { 094 write(out, true, data); 095 } 096 097 private void write(BufferedWriter out, boolean new_line, String... data) throws IOException 098 { 099 for (int x = 0; x < data.length; x++) 100 { 101 out.write(data[x]); 102 } 103 if (new_line) out.write(NEW_LINE); 104 } 105 106 public void write(BufferedWriter out, int indent) throws IOException 107 { 108 String pad0 = getIndent(indent); 109 String pad1 = getIndent(indent + 1); 110 String pad2 = getIndent(indent + 2); 111 112 write(out, pad0, "####################"); 113 write(out, pad0, "# ", name); 114 115 if (comment != null) 116 { 117 write(out, pad0, "#==================="); 118 Splitter splitter = Splitter.onPattern("\r?\n"); 119 120 for (String line : splitter.split(comment)) 121 { 122 write(out, pad0, "# ", line); 123 } 124 } 125 126 write(out, pad0, "####################", NEW_LINE); 127 128 if (!allowedProperties.matchesAllOf(name)) 129 { 130 name = '"' + name + '"'; 131 } 132 133 write(out, pad0, name, " {"); 134 135 Property[] props = properties.values().toArray(new Property[properties.size()]); 136 137 for (int x = 0; x < props.length; x++) 138 { 139 Property prop = props[x]; 140 141 if (prop.comment != null) 142 { 143 if (x != 0) 144 { 145 out.newLine(); 146 } 147 148 Splitter splitter = Splitter.onPattern("\r?\n"); 149 for (String commentLine : splitter.split(prop.comment)) 150 { 151 write(out, pad1, "# ", commentLine); 152 } 153 } 154 155 String propName = prop.getName(); 156 157 if (!allowedProperties.matchesAllOf(propName)) 158 { 159 propName = '"' + propName + '"'; 160 } 161 162 if (prop.isList()) 163 { 164 char type = prop.getType().getID(); 165 166 write(out, pad1, String.valueOf(type), ":", propName, " <"); 167 168 for (String line : prop.getStringList()) 169 { 170 write(out, pad2, line); 171 } 172 173 write(out, pad1, " >"); 174 } 175 else if (prop.getType() == null) 176 { 177 write(out, pad1, propName, "=", prop.getString()); 178 } 179 else 180 { 181 char type = prop.getType().getID(); 182 write(out, pad1, String.valueOf(type), ":", propName, "=", prop.getString()); 183 } 184 } 185 186 for (ConfigCategory child : children) 187 { 188 child.write(out, indent + 1); 189 } 190 191 write(out, pad0, "}", NEW_LINE); 192 } 193 194 private String getIndent(int indent) 195 { 196 StringBuilder buf = new StringBuilder(""); 197 for (int x = 0; x < indent; x++) 198 { 199 buf.append(" "); 200 } 201 return buf.toString(); 202 } 203 204 public boolean hasChanged() 205 { 206 if (changed) return true; 207 for (Property prop : properties.values()) 208 { 209 if (prop.hasChanged()) return true; 210 } 211 return false; 212 } 213 214 void resetChangedState() 215 { 216 changed = false; 217 for (Property prop : properties.values()) 218 { 219 prop.resetChangedState(); 220 } 221 } 222 223 224 //Map bouncer functions for compatibility with older mods, to be removed once all mods stop using it. 225 @Override public int size(){ return properties.size(); } 226 @Override public boolean isEmpty() { return properties.isEmpty(); } 227 @Override public boolean containsKey(Object key) { return properties.containsKey(key); } 228 @Override public boolean containsValue(Object value){ return properties.containsValue(value); } 229 @Override public Property get(Object key) { return properties.get(key); } 230 @Override public Property put(String key, Property value) 231 { 232 changed = true; 233 return properties.put(key, value); 234 } 235 @Override public Property remove(Object key) 236 { 237 changed = true; 238 return properties.remove(key); 239 } 240 @Override public void putAll(Map<? extends String, ? extends Property> m) 241 { 242 changed = true; 243 properties.putAll(m); 244 } 245 @Override public void clear() 246 { 247 changed = true; 248 properties.clear(); 249 } 250 @Override public Set<String> keySet() { return properties.keySet(); } 251 @Override public Collection<Property> values() { return properties.values(); } 252 253 @Override //Immutable copy, changes will NOT be reflected in this category 254 public Set<java.util.Map.Entry<String, Property>> entrySet() 255 { 256 return ImmutableSet.copyOf(properties.entrySet()); 257 } 258 259 public Set<ConfigCategory> getChildren(){ return ImmutableSet.copyOf(children); } 260 261 public void removeChild(ConfigCategory child) 262 { 263 if (children.contains(child)) 264 { 265 children.remove(child); 266 changed = true; 267 } 268 } 269}