/** Called when a block is broken. */
  @Override
  public void onBlockBreak(BlockBreakEvent event) {
    if (event.isCancelled()) {
      return;
    }

    Player player = event.getPlayer();
    WorldConfiguration wcfg = getWorldConfig(player);

    if (!wcfg.itemDurability) {
      ItemStack held = player.getItemInHand();
      if (held.getTypeId() > 0) {
        held.setDurability((short) -1);
        player.setItemInHand(held);
      }
    }

    if (!plugin.getGlobalRegionManager().canBuild(player, event.getBlock())) {
      player.sendMessage(ChatColor.DARK_RED + "You don't have permission for this area.");
      event.setCancelled(true);
      return;
    }

    if (wcfg.getBlacklist() != null) {
      if (!wcfg.getBlacklist()
          .check(
              new BlockBreakBlacklistEvent(
                  plugin.wrapPlayer(player),
                  toVector(event.getBlock()),
                  event.getBlock().getTypeId()),
              false,
              false)) {
        event.setCancelled(true);
        return;
      }

      if (!wcfg.getBlacklist()
          .check(
              new DestroyWithBlacklistEvent(
                  plugin.wrapPlayer(player),
                  toVector(event.getBlock()),
                  player.getItemInHand().getTypeId()),
              false,
              false)) {
        event.setCancelled(true);
        return;
      }
    }

    if (wcfg.isChestProtected(event.getBlock(), player)) {
      player.sendMessage(ChatColor.DARK_RED + "The chest is protected.");
      event.setCancelled(true);
      return;
    }
  }
  /*
   * Called when a block is broken.
   */
  @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
  public void onBlockBreak(BlockBreakEvent event) {
    Player player = event.getPlayer();
    WorldConfiguration wcfg = getWorldConfig(player);

    if (!wcfg.itemDurability) {
      ItemStack held = player.getItemInHand();
      if (held.getTypeId() > 0
          && !(ItemType.usesDamageValue(held.getTypeId())
              || BlockType.usesData(held.getTypeId()))) {
        held.setDurability((short) 0);
        player.setItemInHand(held);
      }
    }

    if (!plugin.getGlobalRegionManager().canBuild(player, event.getBlock())
        || !plugin.getGlobalRegionManager().canConstruct(player, event.getBlock())) {
      player.sendMessage(ChatColor.DARK_RED + "You don't have permission for this area.");
      event.setCancelled(true);
      return;
    }

    if (wcfg.getBlacklist() != null) {
      if (!wcfg.getBlacklist()
          .check(
              new BlockBreakBlacklistEvent(
                  plugin.wrapPlayer(player),
                  toVector(event.getBlock()),
                  event.getBlock().getTypeId()),
              false,
              false)) {
        event.setCancelled(true);
        return;
      }

      if (!wcfg.getBlacklist()
          .check(
              new DestroyWithBlacklistEvent(
                  plugin.wrapPlayer(player),
                  toVector(event.getBlock()),
                  player.getItemInHand().getTypeId()),
              false,
              false)) {
        event.setCancelled(true);
        return;
      }
    }

    if (wcfg.isChestProtected(event.getBlock(), player)) {
      player.sendMessage(ChatColor.DARK_RED + "The chest is protected.");
      event.setCancelled(true);
      return;
    }
  }
  /*
   * Called when a player places a block.
   */
  @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
  public void onBlockPlace(BlockPlaceEvent event) {
    Block blockPlaced = event.getBlock();
    Player player = event.getPlayer();
    World world = blockPlaced.getWorld();

    ConfigurationManager cfg = plugin.getGlobalStateManager();
    WorldConfiguration wcfg = cfg.get(world);

    if (wcfg.useRegions) {
      final Location location = blockPlaced.getLocation();
      if (!plugin.getGlobalRegionManager().canBuild(player, location)
          || !plugin.getGlobalRegionManager().canConstruct(player, location)) {
        player.sendMessage(ChatColor.DARK_RED + "You don't have permission for this area.");
        event.setCancelled(true);
        return;
      }
    }

    if (wcfg.getBlacklist() != null) {
      if (!wcfg.getBlacklist()
          .check(
              new BlockPlaceBlacklistEvent(
                  plugin.wrapPlayer(player), toVector(blockPlaced), blockPlaced.getTypeId()),
              false,
              false)) {
        event.setCancelled(true);
        return;
      }
    }

    if (wcfg.signChestProtection && wcfg.getChestProtection().isChest(blockPlaced.getTypeId())) {
      if (wcfg.isAdjacentChestProtected(event.getBlock(), player)) {
        player.sendMessage(
            ChatColor.DARK_RED + "This spot is for a chest that you don't have permission for.");
        event.setCancelled(true);
        return;
      }
    }

    if (wcfg.simulateSponge && blockPlaced.getTypeId() == 19) {
      if (wcfg.redstoneSponges && blockPlaced.isBlockIndirectlyPowered()) {
        return;
      }

      int ox = blockPlaced.getX();
      int oy = blockPlaced.getY();
      int oz = blockPlaced.getZ();

      SpongeUtil.clearSpongeWater(plugin, world, ox, oy, oz);
    }
  }
  /**
   * Called when a player places a block
   *
   * @param event Relevant event details
   */
  @Override
  public void onBlockPlace(BlockPlaceEvent event) {

    if (event.isCancelled()) {
      return;
    }

    Block blockPlaced = event.getBlock();
    Player player = event.getPlayer();
    World world = blockPlaced.getWorld();

    ConfigurationManager cfg = plugin.getGlobalConfiguration();
    WorldConfiguration wcfg = cfg.get(world);

    if (wcfg.useRegions) {
      if (!plugin.getGlobalRegionManager().canBuild(player, blockPlaced.getLocation())) {
        player.sendMessage(ChatColor.DARK_RED + "You don't have permission for this area.");
        event.setCancelled(true);
        return;
      }
    }

    if (wcfg.getBlacklist() != null) {
      if (!wcfg.getBlacklist()
          .check(
              new BlockPlaceBlacklistEvent(
                  plugin.wrapPlayer(player), toVector(blockPlaced), blockPlaced.getTypeId()),
              false,
              false)) {
        event.setCancelled(true);
        return;
      }
    }

    if (wcfg.simulateSponge && blockPlaced.getTypeId() == 19) {
      if (wcfg.redstoneSponges && blockPlaced.isBlockIndirectlyPowered()) {
        return;
      }

      int ox = blockPlaced.getX();
      int oy = blockPlaced.getY();
      int oz = blockPlaced.getZ();

      clearSpongeWater(world, ox, oy, oz);
    }
  }
  /*
   * Called when a block gets ignited.
   */
  @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
  public void onBlockIgnite(BlockIgniteEvent event) {
    IgniteCause cause = event.getCause();
    Block block = event.getBlock();
    World world = block.getWorld();

    ConfigurationManager cfg = plugin.getGlobalStateManager();
    WorldConfiguration wcfg = cfg.get(world);

    if (cfg.activityHaltToggle) {
      event.setCancelled(true);
      return;
    }
    boolean isFireSpread = cause == IgniteCause.SPREAD;

    if (wcfg.preventLightningFire && cause == IgniteCause.LIGHTNING) {
      event.setCancelled(true);
      return;
    }

    if (wcfg.preventLavaFire && cause == IgniteCause.LAVA) {
      event.setCancelled(true);
      return;
    }

    if (wcfg.disableFireSpread && isFireSpread) {
      event.setCancelled(true);
      return;
    }

    if (wcfg.blockLighter
        && (cause == IgniteCause.FLINT_AND_STEEL || cause == IgniteCause.FIREBALL)
        && event.getPlayer() != null
        && !plugin.hasPermission(event.getPlayer(), "worldguard.override.lighter")) {
      event.setCancelled(true);
      return;
    }

    if (wcfg.fireSpreadDisableToggle && isFireSpread) {
      event.setCancelled(true);
      return;
    }

    if (wcfg.disableFireSpreadBlocks.size() > 0 && isFireSpread) {
      int x = block.getX();
      int y = block.getY();
      int z = block.getZ();

      if (wcfg.disableFireSpreadBlocks.contains(world.getBlockTypeIdAt(x, y - 1, z))
          || wcfg.disableFireSpreadBlocks.contains(world.getBlockTypeIdAt(x + 1, y, z))
          || wcfg.disableFireSpreadBlocks.contains(world.getBlockTypeIdAt(x - 1, y, z))
          || wcfg.disableFireSpreadBlocks.contains(world.getBlockTypeIdAt(x, y, z - 1))
          || wcfg.disableFireSpreadBlocks.contains(world.getBlockTypeIdAt(x, y, z + 1))) {
        event.setCancelled(true);
        return;
      }
    }

    if (wcfg.useRegions) {
      Vector pt = toVector(block);
      Player player = event.getPlayer();
      RegionManager mgr = plugin.getGlobalRegionManager().get(world);
      ApplicableRegionSet set = mgr.getApplicableRegions(pt);

      if (player != null && !plugin.getGlobalRegionManager().hasBypass(player, world)) {
        LocalPlayer localPlayer = plugin.wrapPlayer(player);

        // this is preliminarily handled in the player listener under handleBlockRightClick
        // why it's handled here too, no one knows
        if (cause == IgniteCause.FLINT_AND_STEEL || cause == IgniteCause.FIREBALL) {
          if (!set.allows(DefaultFlag.LIGHTER)
              && !set.canBuild(localPlayer)
              && !plugin.hasPermission(player, "worldguard.override.lighter")) {
            event.setCancelled(true);
            return;
          }
        }
      }

      if (wcfg.highFreqFlags && isFireSpread && !set.allows(DefaultFlag.FIRE_SPREAD)) {
        event.setCancelled(true);
        return;
      }

      if (wcfg.highFreqFlags && cause == IgniteCause.LAVA && !set.allows(DefaultFlag.LAVA_FIRE)) {
        event.setCancelled(true);
        return;
      }

      if (cause == IgniteCause.FIREBALL && event.getPlayer() == null) {
        // wtf bukkit, FIREBALL is supposed to be reserved to players
        if (!set.allows(DefaultFlag.GHAST_FIREBALL)) {
          event.setCancelled(true);
          return;
        }
      }

      if (cause == IgniteCause.LIGHTNING && !set.allows(DefaultFlag.LIGHTNING)) {
        event.setCancelled(true);
        return;
      }
    }
  }
  /** Called when a block gets ignited. */
  @Override
  public void onBlockIgnite(BlockIgniteEvent event) {
    if (event.isCancelled()) {
      return;
    }

    IgniteCause cause = event.getCause();
    Block block = event.getBlock();
    World world = block.getWorld();

    ConfigurationManager cfg = plugin.getGlobalConfiguration();
    WorldConfiguration wcfg = cfg.get(world);

    boolean isFireSpread = cause == IgniteCause.SPREAD;

    if (wcfg.preventLightningFire && cause == IgniteCause.LIGHTNING) {
      event.setCancelled(true);
      return;
    }

    if (wcfg.preventLavaFire && cause == IgniteCause.LAVA) {
      event.setCancelled(true);
      return;
    }

    if (wcfg.disableFireSpread && isFireSpread) {
      event.setCancelled(true);
      return;
    }
    /*
    if (wcfg.blockLighter && cause == IgniteCause.FLINT_AND_STEEL) {
        event.setCancelled(true);
        return;
    }
    */
    if (wcfg.fireSpreadDisableToggle && isFireSpread) {
      event.setCancelled(true);
      return;
    }

    if (wcfg.disableFireSpreadBlocks.size() > 0 && isFireSpread) {
      int x = block.getX();
      int y = block.getY();
      int z = block.getZ();

      if (wcfg.disableFireSpreadBlocks.contains(world.getBlockTypeIdAt(x, y - 1, z))
          || wcfg.disableFireSpreadBlocks.contains(world.getBlockTypeIdAt(x + 1, y, z))
          || wcfg.disableFireSpreadBlocks.contains(world.getBlockTypeIdAt(x - 1, y, z))
          || wcfg.disableFireSpreadBlocks.contains(world.getBlockTypeIdAt(x, y, z - 1))
          || wcfg.disableFireSpreadBlocks.contains(world.getBlockTypeIdAt(x, y, z + 1))) {
        event.setCancelled(true);
        return;
      }
    }

    if (wcfg.useRegions) {
      Vector pt = toVector(block);
      Player player = event.getPlayer();
      RegionManager mgr = plugin.getGlobalRegionManager().get(world);
      ApplicableRegionSet set = mgr.getApplicableRegions(pt);

      if (player != null && !plugin.getGlobalRegionManager().hasBypass(player, world)) {
        LocalPlayer localPlayer = plugin.wrapPlayer(player);

        if (cause == IgniteCause.FLINT_AND_STEEL && !set.canBuild(localPlayer)) {
          event.setCancelled(true);
          return;
        }

        if (cause == IgniteCause.FLINT_AND_STEEL && !set.allows(DefaultFlag.LIGHTER)) {
          event.setCancelled(true);
          return;
        }
      }

      if (wcfg.highFreqFlags && isFireSpread && !set.allows(DefaultFlag.FIRE_SPREAD)) {
        event.setCancelled(true);
        return;
      }

      if (wcfg.highFreqFlags && cause == IgniteCause.LAVA && !set.allows(DefaultFlag.LAVA_FIRE)) {
        event.setCancelled(true);
        return;
      }
    }
  }