package dekk.pw.pokemate;

import com.google.common.geometry. S2LatLng;
import com.google.common.util.concurrent. AtomicDouble;
import com.google.maps.model. DirectionsStep;
import com.google.maps.model. LatLng;
import dekk.pw.pokemate.tasks. Navigate;
import dekk.pw.pokemate.tasks. TagPokestop;
import dekk.pw.pokemate.util. Time;
import org.apache.logging.log4j. LogManager;
import org.apache.logging.log4j. Logger;

import java.util. Random;
import java.util. Timer;
import java.util. TimerTask;
/**
 * Created by TimD on 7/21/2016. 
 */
public class Walking {

    private static final Logger logger = LogManager.getLogger(Walking.class);
    private static final double VARIANCE = Config.getRange();
    private static double getSmallRandom() {
        return Math.random() * 0.0001 - 0.00005;
    }

    public static void setLocation(Context context) {
        setLocation(false, context);
    }

    private static void setLocation(boolean random, Context context) {
        if (random) {
            context.getApi().setLocation(context.getLat().get() + getSmallRandom(), context.getLng().get() + getSmallRandom(), new Random().nextInt(10));
        } else {
            context.getApi().setLocation(context.getLat().get(), context.getLng().get(), new Random().nextInt(10));
        }
    }

    public static void walk( final Context context, S2LatLng end) { // PokeStop Walking
        context.getWalking().set(true);
        S2LatLng start = S2LatLng.fromDegrees(context.getLat().get(), context.getLng().get());
        S2LatLng diff = end.sub(start);
        double distance = start.getEarthDistance(end);
        long timeout = 200L;
        double timeRequired = distance / Config.getSpeed();
        final AtomicDouble stepsRequired = new AtomicDouble(timeRequired / (timeout / 1000D));
        double deltaLat = diff.latDegrees() / stepsRequired.get();
        double deltaLng = diff.lngDegrees() / stepsRequired.get();
        logger.debug("starting to walk");
        //Schedule a timer to walk every 200 ms


        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                context.getApi().setLocation(context.getLat().addAndGet(deltaLat), context.getLng().addAndGet(deltaLng), new Random().nextInt(10));
                stepsRequired.getAndAdd(-1);
                if (stepsRequired.get() <= 0) {
                    logger.debug("Setting a new destination");
                    context.getWalking().set(false);
                    context.addTask(new TagPokestop(context));
                    context.addTask(new Navigate(context, new LatLng(context.getLat().get() - VARIANCE, context.getLng().get() - VARIANCE),
                        new LatLng(context.getLat().get() + VARIANCE, context.getLng().get() + VARIANCE)));
                    cancel();
                }
            }
        }, 0, timeout);
    }

    public static void walk(Context context, DirectionsStep[] steps) {  // Streets Walking
        context.getWalking().set(true);
        if (steps ! = null) {
            for (DirectionsStep step : steps) {
                logger.debug("WALKER Heading to: [" + step.endLocation.lat + ", " + step.endLocation.lng + "]");
                context.getApi().setLocation(step.startLocation.lat, step.startLocation.lng, 0);
                context.getLat().set(step.startLocation.lat);
                context.getLng().set(step.startLocation.lng);
                S2LatLng start = S2LatLng.fromDegrees(step.startLocation.lat, step.startLocation.lng);
                S2LatLng end = S2LatLng.fromDegrees(step.endLocation.lat, step.endLocation.lng);
                S2LatLng diff = end.sub(start);
                double distance;
                distance = start.getEarthDistance(end);
                long timeout = 350L;
                double timeRequired = distance / Config.getSpeed();
                int stepsRequired = (int) (timeRequired / (new Long(timeout).doubleValue() / 1000));
                double deltaLat = diff.latDegrees() / stepsRequired;
                double deltaLng = diff.lngDegrees() / stepsRequired;
                int remainingSteps = stepsRequired;
                while (remainingSteps >= 0) {
                    context.getLat().addAndGet(deltaLat);
                    context.getLng().addAndGet(deltaLng);
                    setLocation(context);
                    try {
                        Thread.sleep(timeout);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                     logger.debug( "Set location: [" + context.getLat().get() + ", " + context.getLng().get() + "]");
                    remainingSteps--;
                }
                logger.debug( "Arrived at: [" + step.endLocation.lat + ", " + step.endLocation.lng + "]");
            }
        }else{
            logger.error("WALKING ERROR");
        }
        context.getWalking().set(false);

    }
}
