    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}