package com.zuehlke.carrera.javapilot.akka.power;

import com.zuehlke.carrera.javapilot.akka.Config;
import com.zuehlke.carrera.javapilot.akka.controller.Autopilot;
import com.zuehlke.carrera.javapilot.akka.model.Sector;
import com.zuehlke.carrera.javapilot.akka.model.SectorHistory;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;

/**
 * Created by Simon Gwerder on 29.11.2015.
 */
public class BaseProfile {

    protected Int2ObjectLinkedOpenHashMap<Power> profile = new Int2ObjectLinkedOpenHashMap<>(20);

    public Int2ObjectLinkedOpenHashMap<Power> getProfile() {
        return profile;
    }

    private double powerDiffFunc(int distance, int velocity, int speedlimit) {
        int diff = Math.abs(speedlimit - velocity);

        if (velocity >= speedlimit - Config.POWERDIFF_DELTA) {
            return -(diff) / ((distance + Config.POWERDIFF_DISTANCE_DELTA) * Config.FACTOR_DOWN);
        }
        else {
            return (diff) / ((distance + Config.POWERDIFF_DISTANCE_DELTA) * Config.FACTOR_UP);
        }
    }

//    private double powerDiffFunc(int distance, int velocity) {
//        int diff = (Config.SPEEDLIMIT - velocity); // Play around with changing sign: (Config.SPEEDLIMIT +- x) - velocity
//        if(velocity < Config.SPEEDLIMIT) {
//            return Math.cbrt(diff) / (distance + 1);
//        }
//        else {
//            return 2 * Math.cbrt(diff) / (distance + 1);
//        }
//    }

    private int approxPotential(SectorHistory sectorHistory) {
        double approxPotential = 0;

        Int2ObjectArrayMap<Sector> affectingCheckpoints = sectorHistory.getAffectingCheckpoints();
        for (int distance : affectingCheckpoints.keySet()) {
            Sector checkpoint = affectingCheckpoints.get(distance);
            Double velocity = checkpoint.getVelocityMeasured();
            if (velocity != null) {
                approxPotential += powerDiffFunc(distance, velocity.intValue(), sectorHistory.getSpeedlimit());
            }
        }

        sectorHistory.clearAffectingCheckpoint(); // Uncool here

        return (int) approxPotential;
    }

    public int changeValue(SectorHistory sectorHistory) {
        int approxPotential = approxPotential(sectorHistory);

        int changeValue = 0;
        if (sectorHistory.hadPenaltyRecently()) {
            changeValue = ((Config.POWER_DOWN * (sectorHistory.getConsecutivePenalty() + 1))) + approxPotential;
        }
        else {
            changeValue = Config.POWER_UP + approxPotential;
        }

        return changeValue;
    }

    public int changeValue(Sector matching) {
        if (matching.getPenalty()) {
            return Config.POWER_DOWN;
        }
        return Config.POWER_UP;
    }

}
