Package com.bergerkiller.bukkit.common.config

Source Code of com.bergerkiller.bukkit.common.config.ConfigurationNode

package com.bergerkiller.bukkit.common.config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.bukkit.configuration.MemorySection;
import org.bukkit.configuration.file.YamlConfiguration;

import com.bergerkiller.bukkit.common.utils.LogicUtil;
import com.bergerkiller.bukkit.common.utils.ParseUtil;
import com.bergerkiller.bukkit.common.utils.StringUtil;

@SuppressWarnings({ "unchecked", "rawtypes" })
public class ConfigurationNode implements Cloneable {
  private final MemorySection source;
  private final Map<String, String> headers;
  private final Set<String> readkeys;

  public ConfigurationNode() {
    this(new HashSet<String>(), new HashMap<String, String>(), new YamlConfiguration());
  }

  private ConfigurationNode(ConfigurationNode source, String root) {
    this.readkeys = source.readkeys;
    this.headers = source.headers;
    MemorySection sect = (MemorySection) source.source.getConfigurationSection(root);
    if (sect == null) {
      this.source = (MemorySection) source.source.createSection(root);
    } else {
      this.source = sect;
    }
    this.setRead();
  }

  private ConfigurationNode(final Set<String> readkeys, final Map<String, String> headers, final MemorySection source) {
    this.readkeys = readkeys;
    this.source = source;
    this.headers = headers;
  }

  /**
   * Checks if this node has a parent, or if it a root node
   *
   * @return True if it has a parent, False if not
   */
  public boolean hasParent() {
    return this.source.getParent() != null;
  }

  /**
   * Checks if this node has sub-nodes or values
   *
   * @return True if this node is empty, False if not
   */
  public boolean isEmpty() {
    return this.getKeys().isEmpty();
  }

  /**
   * Gets the parent configuration node of this Node
   *
   * @return parent node
   */
  public ConfigurationNode getParent() {
    MemorySection sec = (MemorySection) this.source.getParent();
    if (sec == null) {
      return null;
    }
    return new ConfigurationNode(this.readkeys, this.headers, sec);
  }

  /**
   * Gets the full path of a value or node relative to this Configuration Node
   *
   * @param append path, the path to the value or node relative to this Node
   * @return The full path
   */
  public String getPath(String append) {
    String p = this.getPath();
    if (LogicUtil.nullOrEmpty(append)) {
      return p;
    }
    if (LogicUtil.nullOrEmpty(p)) {
      return append;
    }
    return p + "." + append;
  }

  /**
   * Gets the full path of this Configuration Node
   *
   * @return node path
   */
  public String getPath() {
    return this.source.getCurrentPath();
  }

  /**
   * Gets the name of this Configuration Node
   *
   * @return node name
   */
  public String getName() {
    return this.source.getName();
  }

  /**
   * Gets the header of this Node
   *
   * @return The header
   */
  public String getHeader() {
    return this.headers.get(this.getPath());
  }

  /**
   * Gets the header of a value or node
   *
   * @param path to the value or node
   * @return Header at the path specified
   */
  public String getHeader(String path) {
    return this.headers.get(this.getPath(path));
  }

  /**
   * Removes the header for this Node
   */
  public void removeHeader() {
    this.setHeader(null);
  }

  /**
   * Removes the header for a certain value or node
   *
   * @param path to the value or node
   */
  public void removeHeader(String path) {
    this.setHeader(path, null);
  }

  /**
   * Sets the header displayed above this configuration node
   *
   * @param header to set to
   */
  public void setHeader(String header) {
    this.setHeader("", header);
  }

  /**
   * Sets the header displayed above a given configuration node or value
   *
   * @param path to the node or value the header is for
   * @param header to set to
   */
  public void setHeader(String path, String header) {
    if (header == null) {
      this.headers.remove(this.getPath(path));
    } else {
      this.headers.put(this.getPath(path), header);
    }
  }

  /**
   * Adds a new line to the header displayed above this configuration node
   *
   * @param header line to add
   */
  public void addHeader(String header) {
    this.addHeader("", header);
  }

  /**
   * Adds a new line to the header displayed above a given configuration node or value
   *
   * @param path to the node or value the header is for
   * @param header line to add
   */
  public void addHeader(String path, String header) {
    String oldheader = this.getHeader(path);
    if (oldheader == null) {
      this.setHeader(path, header);
    } else {
      this.setHeader(path, oldheader + "\n" + header);
    }
  }

  /**
   * Gets all the headers displayed for this Node and the sub-nodes
   *
   * @return A mapping of keys vs. headers
   */
  public Map<String, String> getHeaders() {
    String root = this.getPath();
    Map<String, String> rval = new HashMap<String, String>(this.headers.size());
    if (LogicUtil.nullOrEmpty(root)) {
      rval.putAll(this.headers);
    } else {
      for (Map.Entry<String, String> entry : this.headers.entrySet()) {
        if (entry.getKey().startsWith(root)) {
          rval.put(entry.getKey(), entry.getValue());
        }
      }
    }
    return rval;
  }

  /**
   * Clears all the headers displayed for this node and the values and sub-nodes in this node
   */
  public void clearHeaders() {
    String root = this.getPath();
    if (root == null || root.length() == 0) {
      this.headers.clear();
    } else {
      Iterator<Map.Entry<String, String>> iter = this.headers.entrySet().iterator();
      while (iter.hasNext()) {
        if (iter.next().getKey().startsWith(root)) {
          iter.remove();
        }
      }
    }

  }

  /**
   * Gets the Memory Section represented by this Configuration Node
   *
   * @return Memory Section of this Node
   */
  public MemorySection getSection() {
    return this.source;
  }

  /**
   * Gets the YamlConfiguration root source for this Configuration
   *
   * @return Yaml Configuration root
   */
  public YamlConfiguration getSource() {
    return (YamlConfiguration) this.source.getRoot();
  }

  /**
   * Checks if a node is contained at the path specified
   *
   * @param path to check at
   * @return True if it is a node, False if not
   */
  public boolean isNode(String path) {
    return this.source.isConfigurationSection(path);
  }

  /**
   * Gets the node at the path specified, creates one if not present
   *
   * @param path to get a node
   * @return the node
   */
  public ConfigurationNode getNode(String path) {
    return new ConfigurationNode(this, path);
  }

  /**
   * Gets all configuration nodes
   *
   * @return Set of configuration nodes
   */
  public Set<ConfigurationNode> getNodes() {
    Set<ConfigurationNode> rval = new HashSet<ConfigurationNode>();
    for (String path : this.getKeys()) {
      if (this.isNode(path)) {
        rval.add(this.getNode(path));
      }
    }
    return rval;
  }

  /**
   * Gets all the values mapped to the keys
   *
   * @return map of the values
   */
  public Map<String, Object> getValues() {
    return this.source.getValues(false);
  }

  /**
   * Gets all the values mapped to the keys of the type specified
   *
   * @param type to convert to
   * @return map of the converted values
   */
  public <T> Map<String, T> getValues(Class<T> type) {
    Map<String, Object> values = this.getValues();
    Iterator<Map.Entry<String, Object>> iter = values.entrySet().iterator();
    while (iter.hasNext()) {
      Map.Entry<String, Object> entry = iter.next();
      T newvalue = ParseUtil.convert(entry.getValue(), type);
      if (newvalue == null) {
        iter.remove();
      } else {
        entry.setValue(newvalue);
      }
    }
    return (Map<String, T>) values;
  }

  /**
   * Gets all the keys of the values
   *
   * @return key set
   */
  public Set<String> getKeys() {
    return this.source.getKeys(false);
  }

  /**
   * Clones this ConfigurationNode in a way that it no longer references the backing file configuration
   */
  @Override
  public ConfigurationNode clone() {
    ConfigurationNode cloned = new ConfigurationNode();
    cloned.setHeader(this.getHeader());
    for (String key : this.getKeys()) {
      if (this.isNode(key)) {
        cloned.set(key, this.getNode(key).clone());
      } else {
        cloned.set(key, this.get(key));
      }
    }
    return cloned;
  }

  public boolean isRead() {
    return this.isRead(null);
  }

  public boolean isRead(String path) {
    return this.readkeys.contains(this.getPath(path));
  }

  public void setRead() {
    this.setRead(null);
  }

  public void setRead(String path) {
    this.setReadFullPath(this.getPath(path));
  }

  private void setReadFullPath(String path) {
    if (this.readkeys.add(path)) {
      int dotindex = path.lastIndexOf('.');
      if (dotindex > 0) {
        this.setReadFullPath(path.substring(0, dotindex));
      }
    }
  }

  /**
   * Trims away all unread values
   */
  public void trim() {
    for (String key : this.getKeys()) {
      if (this.isRead(key)) {
        if (this.isNode(key)) {
          this.getNode(key).trim();
        }
      } else {
        this.remove(key);
      }
    }
  }

  /**
   * Checks if a value is contained at the path specified
   *
   * @param path to check at
   * @return True if a value is contained, False if not
   */
  public boolean contains(String path) {
    return this.source.contains(path);
  }

  /**
   * Clears all values
   */
  public void clear() {
    for (String key : this.getKeys())
      this.remove(key);
  }

  /**
   * Removes the value at the path specified
   *
   * @param path to remove at
   */
  public void remove(String path) {
    this.set(path, null);
  }

  /**
   * Sets a value at a certain path
   *
   * @param path to set
   * @param value to set to
   */
  public void set(String path, Object value) {
    if (value != null) {
      this.setRead(path);
      if (value.getClass().isEnum()) {
        String text = value.toString();
        if (text.equals("true")) {
          value = true;
        } else if (text.equals("false")) {
          value = false;
        } else {
          value = text;
        }
      }
    }
    this.source.set(path, value);
  }

  /**
   * Gets the value at the path as a List
   *
   * @param path to get at
   * @return The value as a List
   */
  public List getList(String path) {
    this.setRead(path);
    return this.source.getList(path);
  }

  /**
   * Gets the value at the path as a List of a given type
   *
   * @param path to get at
   * @param type of the list to get
   * @return The value as a list of the type
   */
  public <T> List<T> getList(String path, Class<T> type) {
    return this.getList(path, type, new ArrayList<T>());
  }

  /**
   * Gets the value at the path as a List of a given type
   *
   * @param path to get at
   * @param type of the list to get
   * @param def list to return if not contained
   * @return The value as a list of the type
   */
  public <T> List<T> getList(String path, Class<T> type, List<T> def) {
    List list = this.getList(path);
    if (list != null) {
      def = new ArrayList<T>();
      T val;
      for (Object o : list) {
        val = ParseUtil.convert(o, type);
        if (val != null)
          def.add(val);
      }
    }
    this.set(path, def);
    return def;
  }

  /**
   * Gets the raw value at the path specified
   *
   * @param path to get at
   * @return the raw value
   */
  public Object get(String path) {
    this.setRead(path);
    return this.source.get(path);
  }

  /**
   * Gets the raw value at the path as the type specified
   *
   * @param path to get at
   * @param type of value to get
   * @return the converted value, or null if not found or invalid
   */
  public <T> T get(String path, Class<T> type) {
    return this.get(path, type, null);
  }

  /**
   * Gets the raw value at the path as the type specified<br>
   * <b>The def value is used to get the type, it can not be null!</b>
   *
   * @param path to get at
   * @param def value to return
   * @return the converted value, or the default value if not found or invalid
   */
  public <T> T get(String path, T def) {
    return this.get(path, (Class<T>) def.getClass(), def);
  }

  /**
   * Gets the raw value at the path as the type specified
   *
   * @param path to get at
   * @param type of value to get
   * @param def value to return
   * @return the converted value, or the default value if not found or invalid
   */
  public <T> T get(String path, Class<T> type, T def) {
    Object rawValue = this.get(path);
    if (type == String.class && rawValue instanceof String[]) {
      // Special conversion to line-by-line String
      // This is needed, as it saves line-split Strings as such
      return (T) StringUtil.join("\n", (String[]) rawValue);
    }
    T rval = ParseUtil.convert(this.get(path), type, def);
    this.set(path, rval);
    return rval;
  }

  /**
   * Shares a single value with a target collection:<br>
   * - Writes the value from this node to the target if possible<br>
   * - Writes the value from the target to this node alternatively<br>
   * - If no value was found at all, both the target and this node get the default value
   *
   * @param target to share the value with
   * @param path to the value to share
   * @param def value to use if no value was found
   */
  public void shareWith(Map<String, Object> target, String path, Object def) {
    Object value = this.get(path);
    if (value != null) {
      target.put(path, value);
    } else {
      value = target.get(path);
      if (value == null) {
        value = def;
        target.put(path, value);
      }
      this.set(path, value);
    }
  }
}
TOP

Related Classes of com.bergerkiller.bukkit.common.config.ConfigurationNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.