/*
 * This file is part of SpongeAPI, licensed under the MIT License (MIT).
 *
 * Copyright (c) SpongePowered <https://www.spongepowered.org>
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.spongepowered.api.event.entity;

import org.spongepowered.api.entity.Entity;
import org.spongepowered.api.entity.EntitySnapshot;
import org.spongepowered.api.event.Cancellable;
import org.spongepowered.api.event.Event;
import org.spongepowered.api.event.world.TargetWorldEvent;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
import org.spongepowered.api.world.explosion.Explosion;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
 * An event that affects multiple {@link Entity} instances as a bulk action.
 * The constraint is that if an action can be deemed as necessary for selective
 * individualized processing, such as {@link DamageEntityEvent},
 * the actioned {@link Event} is handled individually. If a bulk of
 * {@link Entity} instances are being affected, for example by an
 * {@link Explosion} "damaging" a varying amount of {@link Entity} instances.
 * Other cases will be included as necessary.
 */
public interface AffectEntityEvent extends TargetWorldEvent, Cancellable {

    /**
     * Gets an {@link List<EntitySnapshot>} of the entity data
     * un-affected by event changes.
     *
     * @return The ImmutableList
     */
    List<EntitySnapshot> getEntitySnapshots();

    /**
     * Gets the {@link List} who will be affected after event
     * resolution.
     *
     * @return The List
     */
    List<Entity> getEntities();

    /**
     * Sets the {@link List} of entities who will be affected
     * after the event resolution. Note that new entities are
     * not going to be affected.
     *
     * @param entities The entities to affect
     */
    void setEntities(List<Entity> entities);

    /**
     * Filters out {@link Location<World>}'s from
     * {@link AffectEntityEvent#getEntities()} to be affected by this event.
     *
     * <p>Locations for which the predicate returns <code>false</code> will
     * be removed from {@link #getEntities()}.</p>
     *
     * @param predicate The predicate to use for filtering
     * @return The entities removed from {@link #getEntities()}
     */
    default List<Entity> filterEntityLocations(Predicate<Location<World>> predicate) {
        List<Entity> removedEntiies = new ArrayList<>();
        List<Entity> newEntities = new ArrayList<>();
        for (Entity entity : this.getEntities()) {
            if (!predicate.test(entity.getLocation())) {
                removedEntiies.add(entity);
            } else {
                newEntities.add(entity);
            }
        }
        setEntities(newEntities);
        return removedEntiies;
    }

    /**
     * Filters out {@link Entity}'s from {@link AffectEntityEvent#getEntities()}
     * to be affected by this event.
     *
     * <p>Entities for which the predicate returns <code>false</code> will
     * be removed from {@link #getEntities()}.</p>
     *
     * @param predicate The predicate to use for filtering
     * @return The entities removed from {@link #getEntities()}
     */
    default List<? extends Entity> filterEntities(Predicate<Entity> predicate) {
        List<Entity> removedEntiies = new ArrayList<>();
        List<Entity> newEntities = new ArrayList<>();
        for (Entity entity : this.getEntities()) {
            if (!predicate.test(entity)) {
                removedEntiies.add(entity);
            } else {
                newEntities.add(entity);
            }
        }
        setEntities(newEntities);
        return removedEntiies;
    }
}

@@ -1702,24 +1702,51 @@
 .ArrayList;%0A
+import java.util.Iterator;%0A
 import java.
@@ -2727,280 +2727,8 @@
 );%0A%0A
-    /**%0A     * Sets the %7B@link List%7D of entities who will be affected%0A     * after the event resolution. Note that new entities are%0A     * not going to be affected.%0A     *%0A     * @param entities The entities to affect%0A     */%0A    void setEntities(List%3CEntity%3E entities);%0A%0A
     
@@ -3270,32 +3270,33 @@
 ayList%3C%3E();%0A
+%0A
         
 List%3CEntity%3E
@@ -3275,36 +3275,40 @@
 t%3C%3E();%0A%0A        
-List
+Iterator
 %3CEntity%3E newEnti
@@ -3304,49 +3304,84 @@
 ty%3E 
-newEntities = new ArrayList%3C%3E();%0A
+i = this.getEntities().iterator();%0A        while (i.hasNext()) %7B%0A   
         
 for 
@@ -3368,37 +3368,33 @@
 )) %7B%0A           
-for (
+ 
 Entity entity : 
@@ -3391,39 +3391,27 @@
  entity 
-: this.getEntities()) %7B
+= i.next();
 %0A       
@@ -3456,24 +3456,52 @@
 ation())) %7B%0A
+                i.remove();%0A
             
@@ -3549,114 +3549,18 @@
    %7D
- else %7B%0A                newEntities.add(entity);%0A            %7D%0A        %7D%0A        setEntities(newEntities);
+%0A        %7D
 %0A   
@@ -4129,24 +4129,25 @@
 st%3C%3E();%0A
+%0A
         
 List%3CEnt
@@ -4130,36 +4130,40 @@
 t%3C%3E();%0A%0A        
-List
+Iterator
 %3CEntity%3E newEnti
@@ -4159,49 +4159,84 @@
 ty%3E 
-newEntities = new ArrayList%3C%3E();%0A
+i = this.getEntities().iterator();%0A        while (i.hasNext()) %7B%0A   
         
 for 
@@ -4235,13 +4235,9 @@
     
-for (
+ 
 Enti
@@ -4250,31 +4250,19 @@
 ity 
-: this.getEntities()) %7B
+= i.next();
 %0A   
@@ -4297,24 +4297,52 @@
 (entity)) %7B%0A
+                i.remove();%0A
             
@@ -4390,114 +4390,18 @@
    %7D
- else %7B%0A                newEntities.add(entity);%0A            %7D%0A        %7D%0A        setEntities(newEntities);
+%0A        %7D
 %0A   

Fix AffectEntityEvent