package ch.trq.carrera.javapilot.akka;

import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedActor;
import ch.trq.carrera.javapilot.akka.log.LogMessage;
import ch.trq.carrera.javapilot.akka.positiontracker.CarUpdate;
import ch.trq.carrera.javapilot.akka.positiontracker.NewRoundUpdate;
import ch.trq.carrera.javapilot.akka.positiontracker.PositionTracker;
import ch.trq.carrera.javapilot.akka.positiontracker.SectionUpdate;
import ch.trq.carrera.javapilot.akka.trackanalyzer.Direction;
import ch.trq.carrera.javapilot.akka.trackanalyzer.Track;
import ch.trq.carrera.javapilot.akka.trackanalyzer.TrackAndPhysicModelStorage;
import ch.trq.carrera.javapilot.akka.trackanalyzer.TrackSection;
import com.zuehlke.carrera.javapilot.akka.PowerAction;
import com.zuehlke.carrera.relayapi.messages.RoundTimeMessage;
import com.zuehlke.carrera.relayapi.messages.SensorEvent;
import com.zuehlke.carrera.relayapi.messages.VelocityMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Currently not optimizing anything, merely a placeholder.
 */
public class SpeedOptimizer extends UntypedActor {

    private final Logger LOGGER = LoggerFactory.getLogger(SpeedOptimizer.class);
    private ActorRef pilot;
    private final Track track;
    private final int minPower = 120;
    private final int maxTurnPower = 130;
    private final int maxPower = 150;
    private PositionTracker positionTracker;
    private String actorDescription;

    public SpeedOptimizer(ActorRef pilot, TrackAndPhysicModelStorage storage) {
        this.pilot = pilot;
        this.track = storage.getTrack();
        positionTracker = new PositionTracker(storage.getTrack(), storage.getPhysicModel());

        changePower(maxTurnPower);

        actorDescription = getActorDescription();
    }

    public static Props props(ActorRef pilot, TrackAndPhysicModelStorage storage) {
        return Props.create(SpeedOptimizer.class, () -> new SpeedOptimizer(pilot, storage));
    }

    @Override
    public void onReceive(Object message) throws Exception {
        //TODO send updates for completed tracksection, position update
        if (message instanceof SensorEvent) {
            handleSensorEvent((SensorEvent) message);
        } else if (message instanceof VelocityMessage) {
            handleVelocityMessage((VelocityMessage) message);
        } else if (message instanceof RoundTimeMessage) {
            handleRoundTimeMessage((RoundTimeMessage) message);
        } else {
            unhandled(message);
        }
    }

    private void handleRoundTimeMessage(RoundTimeMessage message) {
        // ignore for now
        //positionTracker.roundTimeUpdate(message);
    }

    private void handleVelocityMessage(VelocityMessage message) {
        // ignore for now
        positionTracker.velocityUpdate(message);
    }

    private void handleSensorEvent(SensorEvent event) {
        LogMessage log = new LogMessage(event, System.currentTimeMillis());
        positionTracker.update(event);
        if (!positionTracker.isTurn()) {
            if (positionTracker.getPercentageDistance() > 0.5) {
                changePower(minPower);
            } else {
                changePower(maxPower);
            }
        } else {
            changePower(maxTurnPower);
        }
        //pilot.tell ( new PowerAction(power), getSelf());
        popluateLog(log);
        Track.Position carPosition = positionTracker.getCarPosition();
        pilot.tell(new CarUpdate(carPosition.getSection().getId(), carPosition.getDurationOffset(), carPosition.getPercentage()), getSelf());
        pilot.tell(log, getSelf());
    }

    private void popluateLog(LogMessage log){
        log.setPower(positionTracker.getPower());
        log.setActorDescription(actorDescription);
        log.setPositionRelative(positionTracker.getCarPosition().getDistanceOffset());
        log.settAfterCalculation(System.currentTimeMillis());
    }

    public String getActorDescription(){
        return "SpeedOptimizer";
    }

    private void changePower(int power) {
        pilot.tell(new PowerAction(power), getSelf());
        positionTracker.setPower(power);
    }
}

@@ -757,24 +757,85 @@
 owerAction;%0A
+import com.zuehlke.carrera.relayapi.messages.PenaltyMessage;%0A
 import com.z
@@ -877,32 +877,32 @@
 undTimeMessage;%0A
-
 import com.zuehl
@@ -1183,16 +1183,55 @@
 ctor %7B%0A%0A
+    private final int ZERO_POWER = 0;%0A%0A
     priv
@@ -1399,10 +1399,10 @@
 r = 
-1
 2
+0
 0;%0A 
@@ -1442,9 +1442,9 @@
  = 1
-3
+5
 0;%0A 
@@ -1467,35 +1467,35 @@
  int maxPower = 
-150
+255
 ;%0A    private Po
@@ -2563,32 +2563,147 @@
 sage) message);%0A
+        %7D else if (message instanceof PenaltyMessage)%7B%0A            handlePenaltyMessage((PenaltyMessage) message);%0A
         %7D else %7B
@@ -3799,32 +3799,32 @@
 )), getSelf());%0A
-
         pilot.te
@@ -3842,32 +3842,195 @@
 Self());%0A    %7D%0A%0A
+    private void handlePenaltyMessage(PenaltyMessage message) %7B%0A        // TODO: Set Power to Zero, Wait 3sek, start again%0A        changePower(ZERO_POWER);%0A    %7D%0A%0A
     private void

implement receving PenaltyMessage