package no.javazone;

import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.japi.pf.ReceiveBuilder;
import akka.pattern.Patterns;
import akka.routing.RoundRobinPool;
import scala.concurrent.Await;
import scala.concurrent.duration.Duration;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static no.javazone.util.Timer.time;

public class Akka {

    private static class TaskActor extends AbstractActor {

        public TaskActor() {
            receive(
                ReceiveBuilder
                    .matchEquals("run", msg -> sender().tell(Big.task(), self()))
                    .build()
            );
        }
    }

    private static class TaskRunner extends AbstractActor {

        private ActorRef taskActor;
        private ActorRef originator;

        private int activeTasks = 0;
        private long currentSum = 0;

        public TaskRunner() {
            this.taskActor =
                context().actorOf(
                    Props.create(TaskActor.class).withRouter(new RoundRobinPool(10)),
                    "task"
                );

            receive(
                ReceiveBuilder
                    .matchEquals("start", msg -> {
                        for (int i = 0; i < RunConfig.numRuns; i++) {
                            taskActor.tell("run", self());
                            activeTasks++;
                        }
                        originator = sender();
                    })
                    .match(Long.class, msg -> {
                        currentSum += msg;
                        activeTasks--;
                        if (activeTasks == 0) {
                            originator.tell(Objects.hashCode(currentSum), self());
                        } else if (activeTasks % 1000 == 0) {
                            System.out.println("Remaining: " + activeTasks + " current: " + Objects.hashCode(currentSum));
                        }
                    })
                    .build()
            );
        }
    }

    public static void main(String[] args) throws Exception {
        ActorSystem system = ActorSystem.create();

        time(() -> {
            ActorRef taskRunner = system.actorOf(Props.create(TaskRunner.class), "runner");

            Object result = Await.result(Patterns.ask(taskRunner, "start", 30000), Duration.create(30, TimeUnit.SECONDS));

            System.out.println("Done result: " + result);
        });
        system.shutdown();
    }
}

@@ -372,16 +372,51 @@
 imeUnit;
+%0Aimport java.util.stream.IntStream;
 %0A%0Aimport
@@ -470,24 +470,72 @@
 ass Akka %7B%0A%0A
+    private static final int numRuns = 50_000;%0A%0A
     private 
@@ -1394,18 +1394,8 @@
 i %3C 
-RunConfig.
 numR
@@ -1959,100 +1959,33 @@
     
-System.out.println(%22Remaining: %22 + activeTasks + %22 current: %22 + Objects.hashCode(currentSum)
+printProgress(activeTasks
 );%0A 
@@ -2441,24 +2441,54 @@
 SECONDS));%0A%0A
+            printProgress(0);%0A
             
@@ -2507,16 +2507,18 @@
 rintln(%22
+%5Cn
 Done res
@@ -2579,11 +2579,693 @@
 );%0A    %7D
+%0A%0A    private static void printProgress(int activeTasks) %7B%0A        int mem = (int) ((Runtime.getRuntime().totalMemory() * 100) / Runtime.getRuntime().maxMemory());%0A        StringBuilder builder = new StringBuilder();%0A        IntStream.range(0, mem / 2).forEach(i -%3E builder.append('%5Cu2588'));%0A        builder.append(%22 %22).append(mem).append(%22%25%22);%0A        IntStream.range(Math.max(0, 50 - (50 - builder.length())), 50).forEach(i -%3E builder.append(%22 %22));%0A        long progress = ((numRuns - activeTasks) * 100) / numRuns;%0A        String line = %22%5CrMemory usage: %22 + builder.toString() + %22 (progress: %22 + progress + %22%25)%22;%0A        System.out.print(line);%0A        System.out.flush();%0A    %7D
 %0A%7D%0A

Add fancy output to Akka example.