/** Loads this File Configuration from file */
 public void load() {
   // Ignore loading if file doesn't exist
   if (!file.exists()) {
     return;
   }
   try {
     this.loadFromStream(new FileInputStream(this.file));
   } catch (Throwable t) {
     LOGGER.log(Level.SEVERE, "An error occured while loading file '" + this.file + "'");
     try {
       File backup = new File(this.file.getPath() + ".old");
       StreamUtil.copyFile(this.file, backup);
       LOGGER.log(
           Level.SEVERE,
           "A backup of this (corrupted?) file named '"
               + backup.getName()
               + "' can be found in case you wish to restore",
           t);
     } catch (IOException ex) {
       LOGGER.log(
           Level.SEVERE,
           "A backup of this (corrupted?) file could not be made and its contents may be lost (overwritten)",
           t);
     }
   }
 }
 private void writeHeader(boolean main, BufferedWriter writer, String header, int indent)
     throws IOException {
   if (header != null) {
     for (String headerLine : header.split("\n", -1)) {
       StreamUtil.writeIndent(writer, indent);
       if (main) {
         writer.write(MAIN_HEADER_PREFIX);
         writer.write(headerLine);
       } else if (headerLine.trim().length() > 0) {
         writer.write("# ");
         writer.write(headerLine);
       }
       writer.newLine();
     }
   }
 }
 /** Saves this File Configuration to file */
 public void save() {
   try {
     boolean regen = !this.exists();
     this.saveToStream(StreamUtil.createOutputStream(this.file));
     if (regen) {
       Bukkit.getLogger()
           .log(Level.INFO, "[Configuration] File '" + this.file + "' has been generated");
     }
   } catch (Exception ex) {
     Bukkit.getLogger()
         .log(
             Level.SEVERE,
             "[Configuration] An error occured while saving to file '" + this.file + "':");
     ex.printStackTrace();
   }
 }
  /**
   * Writes this configuration to stream<br>
   * Note: Closes the stream when finished
   *
   * @param stream to write to
   */
  public void saveToStream(OutputStream stream) throws IOException {
    // Get rid of newline characters in text - Bukkit bug prevents proper saving
    for (String key : this.getSource().getKeys(true)) {
      Object value = this.getSource().get(key);
      if (value instanceof String) {
        String text = (String) value;
        if (text.contains("\n")) {
          this.getSource().set(key, Arrays.asList(text.split("\n", -1)));
        }
      }
    }

    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stream));
    try {
      // Write the top header
      writeHeader(true, writer, this.getHeader(), 0);

      // Write other headers and the nodes
      IntHashMap<String> anchorData = new IntHashMap<String>();
      int indent;
      int anchStart, anchEnd, anchId = -1, anchDepth = 0, anchIndent = 0;
      boolean wasAnchor;
      int refStart, refEnd, refId;
      StringBuilder refData = new StringBuilder();
      NodeBuilder node = new NodeBuilder(this.getIndent());
      for (String line : this.getSource().saveToString().split("\n", -1)) {
        line = StringUtil.colorToAmp(line);
        indent = StringUtil.getSuccessiveCharCount(line, ' ');
        line = line.substring(indent);
        wasAnchor = false;
        // ===== Logic start =====
        // Get rid of the unneeded '-characters around certain common names
        if (line.equals("'*':")) {
          line = "*:";
        }

        // Handle a node
        if (node.handle(line, indent)) {
          // Store old anchor data
          if (anchId >= 0 && node.getDepth() <= anchDepth) {
            anchorData.put(anchId, refData.toString());
            refData.setLength(0);
            anchId = refId = -1;
          }

          // Saving a new node: Write the node header
          writeHeader(false, writer, this.getHeader(node.getPath()), indent);

          // Check if the value denotes a reference
          refStart = line.indexOf("*id", node.getName().length());
          refEnd = line.indexOf(' ', refStart);
          if (refEnd == -1) {
            refEnd = line.length();
          }
          if (refStart > 0 && refEnd > refStart) {
            // This is a reference pointer: get id
            refId = ParseUtil.parseInt(line.substring(refStart + 3, refEnd), -1);
            if (refId >= 0) {
              // Obtain the reference data
              String data = anchorData.get(refId);
              if (data != null) {
                // Replace the line with the new data
                line = StringUtil.trimEnd(line.substring(0, refStart)) + " " + data;
              }
            }
          }

          // Check if the value denotes a data anchor
          anchStart = line.indexOf("&id", node.getName().length());
          anchEnd = line.indexOf(' ', anchStart);
          if (anchEnd == -1) {
            anchEnd = line.length();
          }
          if (anchStart > 0 && anchEnd > anchStart) {
            // This is a reference node anchor: get id
            anchId = ParseUtil.parseInt(line.substring(anchStart + 3, anchEnd), -1);
            anchDepth = node.getDepth();
            anchIndent = indent;
            if (anchId >= 0) {
              // Fix whitespace after anchor identifier
              anchEnd += StringUtil.getSuccessiveCharCount(line.substring(anchEnd), ' ');

              // Store the data of this anchor
              refData.append(line.substring(anchEnd));

              // Remove the variable reference from saved data
              line = StringUtil.replace(line, anchStart, anchEnd, "");
            }
            wasAnchor = true;
          }
        }
        if (!wasAnchor && anchId >= 0) {
          // Not an anchor: append anchor data
          refData
              .append('\n')
              .append(StringUtil.getFilledString(" ", indent - anchIndent))
              .append(line);
        }
        // Write the data
        if (LogicUtil.containsChar('\n', line)) {
          for (String part : line.split("\n", -1)) {
            StreamUtil.writeIndent(writer, indent);
            writer.write(part);
            writer.newLine();
          }
        } else {
          StreamUtil.writeIndent(writer, indent);
          writer.write(line);
          writer.newLine();
        }
      }
    } finally {
      writer.close();
    }
  }
 @Override
 public File getWorldFolder(String worldName) {
   return StreamUtil.getFileIgnoreCase(Bukkit.getWorldContainer(), worldName);
 }