public static List<SiegeableData> readList(
      FileConfiguration Source,
      FileConfiguration Target,
      String Node,
      List<SiegeableData> Default) {
    Debugger.Write("Reading SiegableData List From Node:" + Node, Debugger.DebugLevel.Verbose);
    List<?> testcontents = Source.getList(Node);

    List<String> retrievelist = Source.getStringList(Node);
    // getStringList() will return an empty String ArrayList, but will not return null
    // if there are in fact no elements.

    if (testcontents == null) {
      // fill the string list with the contents of the passed default values.
      retrievelist = new ArrayList<String>();
      for (SiegeableData sd : Default) {
        retrievelist.add(sd.toString()); // add the string representation.
      }
    }
    // we set the defaults to the string list, and then parse it after, rather than just setting the
    // default and
    // breaking out because we want ot save those defaults to the configuration node in question.
    List<SiegeableData> result = new ArrayList<SiegeableData>();
    for (String iterate : retrievelist) {
      result.add(new SiegeableData(iterate));
    }

    Target.set(Node, retrievelist);

    return result;
  }
  private String getPlayerDataFile(String sPlayerName) {
    String retval = null;
    try {

      String strPath = playerDataFolderPath + File.separator;

      String scaseSensitive = strPath + sPlayerName;
      String scaseInsensitive = strPath + sPlayerName.toLowerCase();

      File examinepath = new File(strPath);

      File CaseSensitive = null;
      File CaseInsensitive = null;

      // search for file.
      for (File iterate : examinepath.listFiles()) {
        // if it equals the name case-sensitively,

        if (iterate.getName().equals(sPlayerName)) {
          // assign our case sensitive name

          CaseSensitive = iterate;
        } else if (iterate.getName().equalsIgnoreCase(sPlayerName)
            && iterate.getName().toLowerCase().equals(iterate.getName())) {
          // otherwise assign our case insensitive name.

          CaseInsensitive = iterate;
          scaseInsensitive = CaseInsensitive.getName();
        }
      }

      if (CaseSensitive != null
          && CaseInsensitive != null
          && !scaseInsensitive.equals(scaseSensitive)) {
        try {

          // delete caseinsensitive file...
          new File(scaseInsensitive).delete();
          // copy case sensitive version in it's place.

          copyFile(CaseSensitive, CaseInsensitive);
          // CaseInsensitive.renameTo(new File(scaseInsensitive + "-backup"));
          // delete the case sensitive file.

          CaseSensitive.delete();

        } catch (IOException iox) {
          // ignore
        }
      }
      return retval = scaseInsensitive;

    } finally {
      Debugger.Write(
          "Flat: Player Data retrieved for " + sPlayerName + ":" + retval,
          Debugger.DebugLevel.Verbose);
    }
  }
  @Override
  void WorldLoaded(World loaded) {

    int claimsread = 0;
    File claimDataFolder = new File(claimDataFolderPath);
    File[] files = claimDataFolder.listFiles();
    for (File iterate : files) {

      if (getClaimWorld(iterate).equals(loaded.getName())) {
        claimsread++;
        readClaim(iterate);
      }
    }
    Debugger.Write(
        "Read in " + claimsread + " Claims for world:" + loaded.getName(),
        Debugger.DebugLevel.Verbose);
    // System.out.println("Read in " + claimsread + " Claims for world:" +
    // loaded.getName());

  }
  public static void copyFile(File sourceFile, File destFile) throws IOException {
    Debugger.Write(
        "Copying File:" + sourceFile.toString() + " To " + destFile.toString(),
        Debugger.DebugLevel.Verbose);
    BufferedInputStream bsin = new BufferedInputStream(new FileInputStream(sourceFile));
    BufferedOutputStream bsout = new BufferedOutputStream(new FileOutputStream(destFile));
    int chunksize = 16 * 1024;
    int readamount = 0;
    byte[] buffer = new byte[chunksize];
    try {
      // write in chunks of chunksize.
      while ((readamount = bsin.read(buffer, 0, chunksize)) == chunksize) {
        bsout.write(buffer, 0, chunksize);
      }
      // write out the remainder.
      bsout.write(buffer, 0, readamount);

    } catch (Exception exx) {
      exx.printStackTrace();
    } finally {
      bsin.close();
      bsout.close();
    }
  }
  void readClaim(File SourceFile) {
    Debugger.Write("Reading claim from " + SourceFile.getPath(), Debugger.DebugLevel.Verbose);
    // reads a single Claim.
    // loads this claim from the given file.
    if (SourceFile.getPath().startsWith("_")) return;
    Long claimID;
    try {
      claimID = Long.parseLong(SourceFile.getName());
    }

    // because some older versions used a different file name pattern before
    // claim IDs were introduced,
    // those files need to be "converted" by renaming them to a unique ID
    catch (Exception e) {
      claimID = this.nextClaimID;
      this.incrementNextClaimID();
      File newFile =
          new File(claimDataFolderPath + File.separator + String.valueOf(this.nextClaimID));
      SourceFile.renameTo(newFile);
      SourceFile = newFile;
    }
    BufferedReader inStream = null;
    try {
      Claim topLevelClaim = null;
      FileReader fr = new FileReader(SourceFile.getAbsolutePath());
      inStream = new BufferedReader(fr);
      String line = inStream.readLine();
      String subclaimtext = null;
      while (line != null) {

        if (line.toUpperCase().startsWith("SUB:")) {
          subclaimtext = line.substring(4);
          line = inStream.readLine(); // read to the next line.
        }
        // if line is a UUID- it's the UUID. otherwise, we assume it is an older format.
        UUID grabUID = null;
        try {
          grabUID = UUID.fromString(line);
          // if no exception occurs, than it was a UUID;
          // read the next line.
          if (grabUID != null) line = inStream.readLine();
        } catch (Exception ex) {
          Debugger.Write("Exception parsing UUID.", Debugger.DebugLevel.Verbose);

          grabUID = null;
        }

        // first line is lesser boundary corner location
        String splitentry = line.split(";")[0];
        // if the world doesn't exist yet, we need to create a
        // DeferredWorldClaim instance and
        // add it to the dataStore hashMap.
        Location lesserBoundaryCorner = null;
        Location greaterBoundaryCorner = null;
        lesserBoundaryCorner = this.locationFromString(line);
        // second line is greater boundary corner location
        line = inStream.readLine();
        greaterBoundaryCorner = this.locationFromString(line);

        // third line is owner name
        line = inStream.readLine();
        String ownerName = line;

        // is there PlayerData for this gai?

        if (!hasPlayerData(ownerName)
            && GriefPrevention.instance.config_claims_deleteclaimswithunrecognizedowners) {
          // PlayerData not found, don't load this claim.
          GriefPrevention.AddLogEntry(
              "discarded Claim belonging to "
                  + ownerName
                  + " Because there is no PlayerData for that Player.");
          return;
        }

        // fourth line is list of builders
        line = inStream.readLine();
        String[] builderNames = line.split(";");

        // fifth line is list of players who can access containers
        line = inStream.readLine();
        String[] containerNames = line.split(";");

        // sixth line is list of players who can use buttons and
        // switches
        line = inStream.readLine();
        String[] accessorNames = line.split(";");

        // seventh line is list of players who can grant permissions
        line = inStream.readLine();
        if (line == null) line = "";
        String[] managerNames = line.split(";");

        // Eighth line either contains whether the claim can ever be
        // deleted, or the divider for the subclaims
        boolean neverdelete = false;
        line = inStream.readLine();
        if (line == null) line = "";
        if (!line.contains("==========")) {
          neverdelete = Boolean.parseBoolean(line);
        }

        // Sub claims below this line
        while (line != null && !line.contains("==========")) line = inStream.readLine();

        // build a claim instance from those data
        // if this is the first claim loaded from this file, it's the
        // top level claim

        if (topLevelClaim == null) {
          // instantiate
          topLevelClaim =
              new Claim(
                  lesserBoundaryCorner,
                  greaterBoundaryCorner,
                  ownerName,
                  builderNames,
                  containerNames,
                  accessorNames,
                  managerNames,
                  claimID,
                  neverdelete);
          topLevelClaim.setUUID(grabUID);
          // search for another claim overlapping this one

          Claim conflictClaim = this.getClaimAt(topLevelClaim.lesserBoundaryCorner, true);

          // if there is such a claim, delete this file and move on to
          // the next
          if (conflictClaim != null) {
            // System.out.println("Deleting Claim File:" +
            // SourceFile.getAbsolutePath() +
            // " as it is overlapped by ID #" +
            // conflictClaim.getID());
            inStream.close();
            SourceFile.delete();
            line = null;
            continue;
          }

          // otherwise, add this claim to the claims collection
          else {
            topLevelClaim.modifiedDate = new Date(SourceFile.lastModified());

            addClaim(topLevelClaim);

            topLevelClaim.inDataStore = true;
          }
        }

        // otherwise there's already a top level claim, so this must be
        // a subdivision of that top level claim
        else {

          // if it starts with "sub:" then it is a subid.

          // as such, try to read in the subclaim ID.

          Claim subdivision =
              new Claim(
                  lesserBoundaryCorner,
                  greaterBoundaryCorner,
                  topLevelClaim.getOwnerName(),
                  builderNames,
                  containerNames,
                  accessorNames,
                  managerNames,
                  claimID,
                  neverdelete);
          subdivision.setUUID(grabUID);
          try {
            subdivision.id = Long.parseLong(subclaimtext);
          } catch (NumberFormatException nfe) {
            subdivision.id = new Long(-1);
          }
          subdivision.modifiedDate = new Date(SourceFile.lastModified());
          subdivision.parent = topLevelClaim;
          topLevelClaim.children.add(subdivision);
          subdivision.inDataStore = true;
        }

        // move up to the first line in the next subdivision
        line = inStream.readLine();
      }

      inStream.close();
    }
    // We don't need to log any additional error messages for this error.
    catch (WorldNotFoundException e) {
      // Nothing to do here.
    }

    // if there's any problem with the file's content, log an error message
    // and skip it
    catch (Exception e) {
      GriefPrevention.AddLogEntry(
          "Unable to load data for claim \""
              + SourceFile.getName()
              + "\": "
              + e.getClass().getName()
              + "-"
              + e.getMessage());
      e.printStackTrace();
    }

    try {
      if (inStream != null) inStream.close();
    } catch (IOException exception) {

      Debugger.Write("Exception reading claim. ", Debugger.DebugLevel.Verbose);
      Debugger.Write(exception, Debugger.DebugLevel.Verbose);
    }
  }