package com.galvarez.ttw.model;

import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.EntitySystem;
import com.artemis.annotations.Wire;
import com.artemis.utils.ImmutableBag;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.IntArray;
import com.galvarez.ttw.model.components.InfluenceSource;
import com.galvarez.ttw.model.data.Empire;
import com.galvarez.ttw.model.map.MapPosition;
import com.galvarez.ttw.rendering.FadingMessageRenderSystem;
import com.galvarez.ttw.rendering.IconsSystem.Type;
import com.galvarez.ttw.rendering.NotificationsSystem;
import com.galvarez.ttw.rendering.components.Description;
import com.galvarez.ttw.screens.overworld.OverworldScreen;

/**
 * This classes manages epidemics that can regularly happen to influence sources
 * when their power is too far above their growth.
 * 
 * @author Guillaume Alvarez
 */
@Wire
public final class DisasterSystem extends EntitySystem {

  private ComponentMapper<InfluenceSource> sources;

  private ComponentMapper<Empire> empires;

  private ComponentMapper<MapPosition> positions;

  private NotificationsSystem notifications;

  private FadingMessageRenderSystem fadingSystem;

  private final OverworldScreen screen;

  @SuppressWarnings("unchecked")
  public DisasterSystem(OverworldScreen screen) {
    super(Aspect.getAspectForAll(InfluenceSource.class));
    this.screen = screen;
  }

  @Override
  protected boolean checkProcessing() {
    return true;
  }

  @Override
  protected void processEntities(ImmutableBag<Entity> entities) {
    Entity target = getDisasterTarget(entities);
    if (target != null)
      createDisaster(target);
  }

  /** Return the entity targeted by a disaster this turn, null if none is. */
  private Entity getDisasterTarget(ImmutableBag<Entity> entities) {
    Array<Entity> empires = new Array<>(entities.size() / 2);
    IntArray chances = new IntArray(entities.size() / 2);
    int total = 0;

    for (Entity e : entities) {
      InfluenceSource source = sources.get(e);
      int unhealth = source.power() - source.health;
      if (unhealth > 0) {
        empires.add(e);
        chances.add(unhealth);
        total += unhealth;
      }
    }

    if (total > 100 || MathUtils.random(100) > total) {
      int target = MathUtils.random(total);
      int counter = 0;
      for (int i = 0; i < chances.size; i++) {
        counter += chances.get(i);
        if (counter > target)
          return empires.get(i);
      }
    }

    return null;
  }

  /** Apply the disaster effect and notify player. */
  private void createDisaster(Entity target) {
    InfluenceSource source = sources.get(target);
    source.setPower(source.health / 2);

    fadingSystem.createFadingIcon(Type.DISEASE, empires.get(target).color, positions.get(target), 3f);
    notifications.addNotification(() -> screen.select(target, false), null, Type.DISEASE, "Mortal disease strikes %s!",
        target.getComponent(Description.class));
  }
}

@@ -26,16 +26,51 @@
 model;%0A%0A
+import static java.lang.Math.max;%0A%0A
 import c
@@ -275,112 +275,52 @@
 com.
-badlogic.gdx.math.MathUtils;%0Aimport com.badlogic.gdx.utils.Array;%0Aimport com.badlogic.gdx.utils.IntArray
+galvarez.ttw.model.EventsSystem.EventHandler
 ;%0Aim
@@ -985,16 +985,40 @@
 ySystem 
+implements EventHandler 
 %7B%0A%0A  pri
@@ -1466,24 +1466,158 @@
 creen;%0A  %7D%0A%0A
+  @Override%0A  protected void initialize() %7B%0A    super.initialize();%0A%0A    world.getSystem(EventsSystem.class).addEventType(this);%0A  %7D%0A%0A
   @Override%0A
@@ -1764,434 +1764,86 @@
     
-Entity target = getDisasterTarget(entities);%0A    if (target != null)%0A      createDisaster(target);%0A  %7D%0A%0A  /** Return the entity targeted by a disaster this turn, null if none is. */%0A  private Entity getDisasterTarget(ImmutableBag%3CEntity%3E entities) %7B%0A    Array%3CEntity%3E empires = new Array%3C%3E(entities.size() / 2);%0A    IntArray chances = new IntArray(entities.size() / 2);%0A    int total = 0;%0A%0A    for (Entity e : entities
+// done from events%0A  %7D%0A%0A  @Override%0A  public int getProgress(Entity e
 ) %7B%0A    
   In
@@ -1838,18 +1838,16 @@
 ) %7B%0A    
- 
- 
 Influenc
@@ -1875,26 +1875,24 @@
 ces.get(e);%0A
-  
     int unhe
@@ -1938,523 +1938,79 @@
     
-  if (unhealth %3E 0) %7B%0A        empires.add(e);%0A        chances.add(unhealth);%0A        total += unhealth;%0A      %7D%0A    %7D%0A%0A    if (total %3E 100 %7C%7C MathUtils.random(100) %3E total) %7B%0A      int target = MathUtils.random(total);%0A      int counter = 0;%0A      for (int i = 0; i %3C chances.size; i++) %7B%0A        counter += chances.get(i);%0A        if (counter %3E target)%0A          return empires.get(i);%0A      %7D%0A    %7D%0A%0A    return null;%0A  %7D%0A%0A  /** Apply the disaster effect and notify player. */%0A  private void createDisas
+return max(0, unhealth);%0A  %7D%0A%0A  @Override%0A  public void execu
 te
-r
 (Entity 
 targ
@@ -2005,22 +2005,17 @@
 (Entity 
-target
+e
 ) %7B%0A    
@@ -2051,22 +2051,17 @@
 ces.get(
-target
+e
 );%0A    s
@@ -2156,22 +2156,17 @@
 res.get(
-target
+e
 ).color,
@@ -2180,22 +2180,17 @@
 ons.get(
-target
+e
 ), 3f);%0A
@@ -2243,22 +2243,17 @@
 .select(
-target
+e
 , false)
@@ -2316,14 +2316,9 @@
     
-target
+e
 .get
@@ -2352,10 +2352,11 @@
 ));%0A  %7D%0A
+%0A
 %7D%0A

Handle disasters through the events system.