public List<Spawner> loadAllSpawnersFromWorld(World w) {
    List<Spawner> list = new ArrayList<Spawner>();

    String ch = File.separator;
    String worldDir = w.getWorldFolder() + ch + "cs_data" + ch;
    String entityDir = worldDir + ch + "entity";
    String spawnerDir = worldDir + ch + "spawner";

    File spawnerFiles = new File(spawnerDir);
    File entityFiles = new File(entityDir);

    if (!spawnerFiles.exists()) spawnerFiles.mkdirs();

    if (!entityFiles.exists()) entityFiles.mkdirs();

    for (File spawnerFile : spawnerFiles.listFiles()) {

      Spawner s = PLUGIN.getFileManager().loadSpawner(spawnerFile);
      List<Integer> sEntsAsIDs = s.getTypeData();
      List<SpawnableEntity> sEnts = new ArrayList<SpawnableEntity>();
      ArrayList<SpawnableEntity> containedEntities = new ArrayList<SpawnableEntity>();

      for (Integer i : sEntsAsIDs) {
        sEnts.add(CustomSpawners.getEntity(i.toString()));
      }

      for (File f : entityFiles.listFiles()) {
        containedEntities.add(PLUGIN.getFileManager().loadEntity(f));
      }

      if (containedEntities.containsAll(sEnts)) list.add(s);
    }

    return list;
  }
  @Override
  protected List<DataSourceField> addDataSourceFields() {
    List<DataSourceField> fields = super.addDataSourceFields();

    DataSourceField idDataField = new DataSourceIntegerField("id", MSG.common_title_id(), 50);
    idDataField.setPrimaryKey(true);
    idDataField.setCanEdit(false);
    fields.add(idDataField);

    DataSourceTextField nameDataField =
        new DataSourceTextField(NAME.propertyName(), NAME.title(), 200);
    nameDataField.setCanEdit(false);
    fields.add(nameDataField);

    DataSourceTextField descriptionDataField =
        new DataSourceTextField(DESCRIPTION.propertyName(), DESCRIPTION.title());
    descriptionDataField.setCanEdit(false);
    fields.add(descriptionDataField);

    DataSourceTextField typeNameDataField =
        new DataSourceTextField(TYPE.propertyName(), TYPE.title());
    fields.add(typeNameDataField);

    DataSourceTextField pluginNameDataField =
        new DataSourceTextField(PLUGIN.propertyName(), PLUGIN.title());
    fields.add(pluginNameDataField);

    DataSourceTextField categoryDataField =
        new DataSourceTextField(CATEGORY.propertyName(), CATEGORY.title());
    fields.add(categoryDataField);

    return fields;
  }
  @Override
  public ListGridRecord copyValues(ResourceGroupComposite from) {
    ListGridRecord record = new ListGridRecord();
    record.setAttribute("group", from);
    record.setAttribute("id", from.getResourceGroup().getId());
    record.setAttribute(NAME.propertyName(), from.getResourceGroup().getName());
    record.setAttribute(DESCRIPTION.propertyName(), from.getResourceGroup().getDescription());
    record.setAttribute(CATEGORY.propertyName(), from.getResourceGroup().getGroupCategory().name());

    record.setAttribute("explicitCount", String.valueOf(from.getExplicitCount()));
    record.setAttribute("explicitDown", String.valueOf(from.getExplicitDown()));
    record.setAttribute("explicitDisabled", String.valueOf(from.getExplicitDisabled()));
    record.setAttribute("implicitCount", String.valueOf(from.getImplicitCount()));
    record.setAttribute("implicitDown", String.valueOf(from.getImplicitDown()));
    record.setAttribute("implicitDisabled", String.valueOf(from.getImplicitDisabled()));

    record.setAttribute(AVAIL_CHILDREN.propertyName(), getExplicitFormatted(from));
    record.setAttribute(AVAIL_DESCENDANTS.propertyName(), getImplicitFormatted(from));

    if (from.getResourceGroup().getResourceType() != null) {
      record.setAttribute("resourceType", from.getResourceGroup().getResourceType());
      record.setAttribute(TYPE.propertyName(), from.getResourceGroup().getResourceType().getName());
      record.setAttribute(
          PLUGIN.propertyName(), from.getResourceGroup().getResourceType().getPlugin());
    }

    return record;
  }
  @Override
  public void run(SpawnableEntity entity, CommandSender sender, String subCommand, String[] args) {
    String in = getValue(args, 0, "false");
    entity.setSaddled(Boolean.parseBoolean(in));

    PLUGIN.sendMessage(sender, getSuccessMessage(entity, "saddled", in));
  }
  // Load spawners and entities from world files
  public List<Spawner> loadData() {

    Iterator<World> worldItr = PLUGIN.getServer().getWorlds().iterator();
    List<Spawner> loaded = new ArrayList<Spawner>();

    while (worldItr.hasNext()) {
      World w = worldItr.next();

      Iterator<SpawnableEntity> entitiesFromWorld = loadAllEntitiesFromWorld(w).iterator();
      while (entitiesFromWorld.hasNext()) {
        SpawnableEntity e = entitiesFromWorld.next();
        int nextId = PLUGIN.getNextEntityId();
        if (CustomSpawners.entities.containsKey(e.getId())) {
          e = e.cloneWithNewId(nextId);
        }
        CustomSpawners.entities.put(nextId, e);
      }

      Iterator<Spawner> spawnersFromWorld = loadAllSpawnersFromWorld(w).iterator();
      while (spawnersFromWorld.hasNext()) {
        Spawner s = spawnersFromWorld.next();
        boolean sameSpawner = false;

        for (Spawner s1 : CustomSpawners.spawners.values()) {
          if (s1.getLoc().equals(s.getLoc())) {
            sameSpawner = true;
          }
        }

        if (sameSpawner) {
          continue;
        } else {
          int nextId = PLUGIN.getNextSpawnerId();
          Spawner s1 = PLUGIN.cloneWithNewId(s);
          CustomSpawners.spawners.put(nextId, s1);
          loaded.add(s1);
        }
      }
    }

    return loaded;
  }
  @Override
  public void run(CommandSender sender, String subCommand, String[] args) {
    if (subCommand.equals("import")) {

      PLUGIN.sendMessage(sender, ChatColor.GREEN + "Loading CustomSpawners data from worlds...");

      int amountLoaded = loadData().size();

      PLUGIN.sendMessage(
          sender,
          ChatColor.GREEN
              + "Loaded "
              + ChatColor.GOLD
              + amountLoaded
              + ChatColor.GREEN
              + " spawners from worlds in server.");

    } else if (subCommand.equals("export")) {

      PLUGIN.sendMessage(sender, ChatColor.GREEN + "Exporting CustomSpawners data to worlds...");

      Iterator<Spawner> sp = CustomSpawners.spawners.values().iterator();
      int amountLoaded = 0;
      while (sp.hasNext()) {
        PLUGIN.saveCustomSpawnerToWorld(sp.next());
        amountLoaded++;
      }

      PLUGIN.sendMessage(
          sender,
          ChatColor.GREEN
              + "Exported "
              + ChatColor.GOLD
              + amountLoaded
              + ChatColor.GREEN
              + " spawners to worlds.");
    }
  }
  public List<SpawnableEntity> loadAllEntitiesFromWorld(World w) {
    List<SpawnableEntity> list = new ArrayList<SpawnableEntity>();

    String ch = File.separator;
    String worldDir = w.getWorldFolder() + ch + "cs_data" + ch;
    String entityDir = worldDir + ch + "entity";

    File entityFiles = new File(entityDir);

    if (!entityFiles.exists()) entityFiles.mkdirs();

    for (File f : entityFiles.listFiles()) {
      list.add(PLUGIN.getFileManager().loadEntity(f));
    }

    return list;
  }
  @Override
  public ResourceGroupComposite copyValues(Record from) {
    Integer idAttrib = from.getAttributeAsInt("id");
    String nameAttrib = from.getAttribute(NAME.propertyName());
    String descriptionAttrib = from.getAttribute(DESCRIPTION.propertyName());
    String typeNameAttrib = from.getAttribute(TYPE.propertyName());

    ResourceGroup rg = new ResourceGroup(nameAttrib);
    rg.setId(idAttrib);
    rg.setDescription(descriptionAttrib);
    if (typeNameAttrib != null) {
      ResourceType rt = new ResourceType();
      rt.setName(typeNameAttrib);
      String pluginNameAttrib = from.getAttribute(PLUGIN.propertyName());
      rt.setPlugin(pluginNameAttrib);
      rg.setResourceType(rt);
    }

    Long explicitCount = Long.valueOf(from.getAttribute("explicitCount"));
    Long explicitDown = Long.valueOf(from.getAttribute("explicitDown"));
    Long explicitUnknown = Long.valueOf(from.getAttribute("explicitUnknown"));
    Long explicitDisabled = Long.valueOf(from.getAttribute("explicitDisabled"));
    Long implicitCount = Long.valueOf(from.getAttribute("implicitCount"));
    Long implicitDown = Long.valueOf(from.getAttribute("implicitDown"));
    Long implicitUnknown = Long.valueOf(from.getAttribute("implicitUnknown"));
    Long implicitDisabled = Long.valueOf(from.getAttribute("implicitDisabled"));

    ResourceGroupComposite composite =
        new ResourceGroupComposite(
            explicitCount,
            explicitDown,
            explicitUnknown,
            explicitDisabled,
            implicitCount,
            implicitDown,
            implicitUnknown,
            implicitDisabled,
            rg);

    return composite;
  }
  private IHyperlink openPOMbyID(Node current, final ITextViewer viewer, int offset) {
    while (current != null && !(current instanceof Element)) {
      current = current.getParentNode();
    }
    if (current == null) {
      return null;
    }
    current = current.getParentNode();
    if (current == null || !(current instanceof Element)) {
      return null;
    }
    Element parent = (Element) current;
    String parentName = parent.getNodeName();
    if (DEPENDENCY.equals(parentName)
        || PARENT.equals(parentName)
        || PLUGIN.equals(parentName)
        || "reportPlugin".equals(parentName)
        || EXTENSION.equals(parentName)) {
      final Node groupId = XmlUtils.findChild(parent, GROUP_ID);
      final Node artifactId = XmlUtils.findChild(parent, ARTIFACT_ID);
      final Node version = XmlUtils.findChild(parent, VERSION);
      final MavenProject prj = XmlUtils.extractMavenProject(viewer);

      IHyperlink pomHyperlink =
          new IHyperlink() {
            public IRegion getHyperlinkRegion() {
              // the goal here is to have the groupid/artifactid/version combo underscored by the
              // link.
              // that will prevent underscoring big portions (like plugin config) underscored and
              // will also handle cases like dependencies within plugins.
              int max =
                  groupId != null ? ((IndexedRegion) groupId).getEndOffset() : Integer.MIN_VALUE;
              int min =
                  groupId != null ? ((IndexedRegion) groupId).getStartOffset() : Integer.MAX_VALUE;
              max =
                  Math.max(
                      max,
                      artifactId != null
                          ? ((IndexedRegion) artifactId).getEndOffset()
                          : Integer.MIN_VALUE);
              min =
                  Math.min(
                      min,
                      artifactId != null
                          ? ((IndexedRegion) artifactId).getStartOffset()
                          : Integer.MAX_VALUE);
              max =
                  Math.max(
                      max,
                      version != null
                          ? ((IndexedRegion) version).getEndOffset()
                          : Integer.MIN_VALUE);
              min =
                  Math.min(
                      min,
                      version != null
                          ? ((IndexedRegion) version).getStartOffset()
                          : Integer.MAX_VALUE);
              return new Region(min, max - min);
            }

            public String getHyperlinkText() {
              return NLS.bind(
                  Messages.PomHyperlinkDetector_hyperlink_pattern,
                  XmlUtils.getTextValue(groupId),
                  XmlUtils.getTextValue(artifactId));
            }

            public String getTypeLabel() {
              return "pom"; //$NON-NLS-1$
            }

            public void open() {
              new Job(Messages.PomHyperlinkDetector_job_name) {
                protected IStatus run(IProgressMonitor monitor) {
                  // TODO resolve groupId if groupId==null
                  String gridString =
                      groupId == null
                          ? "org.apache.maven.plugins"
                          : XmlUtils.getTextValue(groupId); // $NON-NLS-1$
                  String artidString =
                      artifactId == null ? null : XmlUtils.getTextValue(artifactId);
                  String versionString = version == null ? null : XmlUtils.getTextValue(version);
                  if (prj != null
                      && gridString != null
                      && artidString != null
                      && (versionString == null || versionString.contains("${"))) { // $NON-NLS-1$
                    try {
                      // TODO how do we decide here if the hyperlink is a dependency or a plugin
                      // hyperlink??
                      versionString =
                          PomTemplateContext.extractVersion(
                              prj,
                              null,
                              versionString,
                              gridString,
                              artidString,
                              PomTemplateContext.EXTRACT_STRATEGY_DEPENDENCY);

                    } catch (CoreException e) {
                      versionString = null;
                    }
                  }
                  if (versionString == null) {
                    return Status.OK_STATUS;
                  }
                  OpenPomAction.openEditor(gridString, artidString, versionString, monitor);
                  // TODO: it's preferable to open the xml page, but this code will blink and open
                  // overview first and later switch. looks bad
                  //            Display.getDefault().syncExec(new Runnable() {
                  //              public void run() {
                  //                selectEditorPage(page);
                  //              }
                  //            });
                  return Status.OK_STATUS;
                }
              }.schedule();
            }
          };
      return pomHyperlink;
    }
    return null;
  }
  static ManagedArtifactRegion findManagedArtifactRegion(
      Node current, ITextViewer textViewer, int offset) {
    while (current != null && !(current instanceof Element)) {
      current = current.getParentNode();
    }
    if (current != null) {
      Node artNode = null;
      Node groupNode = null;
      if (ARTIFACT_ID.equals(current.getNodeName())) { // $NON-NLS-1$
        artNode = current;
      }
      if (GROUP_ID.equals(current.getNodeName())) { // $NON-NLS-1$
        groupNode = current;
      }
      // only on artifactid and groupid elements..
      if (artNode == null && groupNode == null) {
        return null;
      }
      Node root = current.getParentNode();
      boolean isDependency = false;
      boolean isPlugin = false;
      if (root != null) {
        String name = root.getNodeName();
        if (DEPENDENCY.equals(name)) { // $NON-NLS-1$
          isDependency = true;
        }
        if (PLUGIN.equals(name)) { // $NON-NLS-1$
          isPlugin = true;
        }
      } else {
        return null;
      }
      if (!isDependency && !isPlugin) {
        // some kind of other identifier
        return null;
      }
      // now see if version is missing
      NodeList childs = root.getChildNodes();
      for (int i = 0; i < childs.getLength(); i++) {
        Node child = childs.item(i);
        if (child instanceof Element) {
          Element el = (Element) child;
          if (VERSION.equals(el.getNodeName())) { // $NON-NLS-1$
            return null;
          }
          if (artNode == null && ARTIFACT_ID.equals(el.getNodeName())) { // $NON-NLS-1$
            artNode = el;
          }
          if (groupNode == null && GROUP_ID.equals(el.getNodeName())) { // $NON-NLS-1$
            groupNode = el;
          }
        }
      }
      if (groupNode != null && artNode != null) {
        assert groupNode instanceof IndexedRegion;
        assert artNode instanceof IndexedRegion;

        IndexedRegion groupReg = (IndexedRegion) groupNode;
        IndexedRegion artReg = (IndexedRegion) artNode;
        int startOffset = Math.min(groupReg.getStartOffset(), artReg.getStartOffset());
        int length = Math.max(groupReg.getEndOffset(), artReg.getEndOffset()) - startOffset;
        String groupId = XmlUtils.getTextValue(groupNode);
        String artifactId = XmlUtils.getTextValue(artNode);
        final MavenProject prj = XmlUtils.extractMavenProject(textViewer);
        if (prj != null) {
          // now we can create the region I guess,
          return new ManagedArtifactRegion(
              startOffset, length, groupId, artifactId, isDependency, isPlugin, prj);
        }
      }
    }
    return null;
  }
  @Override
  public void run(SpawnableEntity entity, CommandSender sender, String subCommand, String[] args) {

    /*
     * Syntax:
     *
     * <attribute name> <base> [<modifier name>,<operator>,<amount>;...]
     */

    if (subCommand.equals("clearattributes")) {
      entity.setAttributes(new ArrayList<Attribute>());
      PLUGIN.sendMessage(
          sender,
          ChatColor.GREEN
              + "Successfully cleared attributes on entity "
              + ChatColor.GOLD
              + PLUGIN.getFriendlyName(entity)
              + ChatColor.GREEN
              + ".");
      return;
    }

    String in = getValue(args, 0, "generic.maxHealth");

    VanillaAttribute att = PLUGIN.parseAttribute(in);

    if (att == null) {
      PLUGIN.sendMessage(sender, ChatColor.RED + "That is not an attribute type.");
      return;
    }

    String in0 = getValue(args, 1, "" + att.getDefaultBase());

    if (!CustomSpawners.isDouble(in0)) {
      PLUGIN.sendMessage(sender, ChatColor.RED + "The base value must be number.");
      return;
    }

    double base = Double.parseDouble(in0);

    if (base < att.getMinimum() || (base > att.getMaximum() && att.getMaximum() != -1)) {
      PLUGIN.sendMessage(
          sender,
          ChatColor.RED
              + "The base value must be between the "
              + "minimum and maximum values of the attribute.");
      return;
    }

    Attribute newAtt = new Attribute(att);
    newAtt.setBase(base);

    String in1 = getValue(args, 2, "");

    if (!in1.isEmpty()) {
      String[] splitMods = in1.split(";");

      for (String mod : splitMods) {
        String[] splitCommas = mod.split(",");
        String modName = splitCommas[0];
        String operator = splitCommas[1];
        String amount = splitCommas[2];

        Operation op = Operation.fromName(operator);

        if (op == null && CustomSpawners.isInteger(operator))
          op = Operation.fromId(Integer.parseInt(operator));

        if (op == null) {
          PLUGIN.sendMessage(
              sender, ChatColor.RED + "\"" + modName + "\" is not an operation for modifiers.");
          return;
        }

        if (!CustomSpawners.isDouble(amount)) {
          PLUGIN.sendMessage(sender, ChatColor.RED + "The amount for a modifier must be a number.");
          return;
        }

        double amt = Double.parseDouble(amount);

        Modifier newMod = new Modifier(modName, op, amt);
        newAtt.addModifier(newMod);
      }
    }

    Iterator<Attribute> attItr = entity.getAttributes().iterator();
    while (attItr.hasNext()) {
      Attribute a = attItr.next();
      if (a.getAttribute().equals(newAtt.getAttribute())) {
        attItr.remove();
        PLUGIN.sendMessage(sender, ChatColor.GOLD + "Replaced attribute with same type.");
      }
    }

    if (subCommand.equals("addattribute")) {
      entity.addAttribute(newAtt);
      PLUGIN.sendMessage(
          sender,
          ChatColor.GREEN
              + "Successfully added attribute "
              + ChatColor.GOLD
              + in
              + ChatColor.GREEN
              + " to entity "
              + ChatColor.GOLD
              + PLUGIN.getFriendlyName(entity)
              + ChatColor.GREEN
              + ".");
    } else if (subCommand.equals("setattribute")) {
      List<Attribute> list = new ArrayList<Attribute>();
      list.add(newAtt);
      entity.setAttributes(list);
      PLUGIN.sendMessage(
          sender,
          ChatColor.GREEN
              + "Successfully set attribute to "
              + ChatColor.GOLD
              + in
              + ChatColor.GREEN
              + " on entity "
              + ChatColor.GOLD
              + PLUGIN.getFriendlyName(entity)
              + ChatColor.GREEN
              + ".");
    }
  }
  @SuppressWarnings("deprecation")
  @Override
  public void run(Spawner spawner, CommandSender sender, String subCommand, String[] args) {

    if (!(sender instanceof Player)) {
      PLUGIN.sendMessage(sender, NO_CONSOLE);
      return;
    }

    Player player = (Player) sender;

    SpawnableEntity entity = null;

    String in = getValue(args, 0, "");

    if (in.isEmpty()) {
      Integer selection = CustomSpawners.entitySelection.get(player);
      if (selection == null) {
        PLUGIN.sendMessage(sender, NO_ID);
        return;
      }
      entity = CustomSpawners.getEntity(selection);
    } else {
      entity = CustomSpawners.getEntity(in);
    }

    if (entity == null) {
      PLUGIN.sendMessage(sender, NO_ID);
      return;
    }

    Block target =
        player.getTargetBlock(CustomSpawners.transparent, CONFIG.getInt("players.maxDistance", 5));

    if (target == null) {
      PLUGIN.sendMessage(
          player, ChatColor.RED + "You must look at a block to make a spawner there.");
      return;
    }

    if (target.getType().equals(Material.AIR)) {
      PLUGIN.sendMessage(
          player, ChatColor.RED + "You must look at a block to make a spawner there.");
      return;
    }

    Spawner newSpawner = PLUGIN.createSpawner(entity, target.getLocation());

    if (CONFIG.getBoolean("data.autosave") && CONFIG.getBoolean("data.saveOnCreate")) {
      PLUGIN.getFileManager().autosave(newSpawner);
    }

    // TODO Add this to wiki.
    Group addTo = null;
    if (sender instanceof Player) {
      Player p = (Player) sender;
      if (CustomSpawners.groupSelection.containsKey(p)) {
        addTo = CustomSpawners.getGroup(CustomSpawners.groupSelection.get(sender));
      }
    } else {
      if (CustomSpawners.consoleGroup != -1) {
        addTo = CustomSpawners.getGroup(CustomSpawners.consoleGroup);
      }
    }

    if (addTo != null
        && CONFIG.getBoolean("players.groupAutoAdd", false)
        && addTo.getType().equals(Group.Type.SPAWNER)) {
      addTo.addItem(newSpawner);
      PLUGIN.sendMessage(
          sender,
          ChatColor.GREEN
              + "Successfully created a new "
              + ChatColor.GOLD
              + in
              + ChatColor.GREEN
              + " spawner with ID number "
              + ChatColor.GOLD
              + newSpawner.getId()
              + ChatColor.GREEN
              + "! This spawner was added to group "
              + ChatColor.GOLD
              + PLUGIN.getFriendlyName(addTo)
              + ChatColor.GREEN
              + ".");
    }

    PLUGIN.sendMessage(
        player,
        ChatColor.GREEN
            + "Successfully created a "
            + ChatColor.GOLD
            + PLUGIN.getFriendlyName(entity)
            + ChatColor.GREEN
            + " spawner with ID "
            + ChatColor.GOLD
            + PLUGIN.getFriendlyName(newSpawner)
            + ChatColor.GREEN
            + "!");
  }