import processing.core.PApplet;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.jgrapht.*;
import org.jgrapht.alg.DijkstraShortestPath;
import org.jgrapht.graph.*;

public class Car {
  PApplet p;
  private RoadEdge road;
  private float angle, velocity, maxVelocity;
  private static int nrID = 0;
  private int ID;
  private float pathIdx;
  List<RoadEdge> route;
  private int routeIdx;
  private int red, green, blue;

  private float posX, posY;

  Car(PApplet parent) {
    Random r = new Random();
    route = new ArrayList<RoadEdge>();
    p = parent;
    road = null;
    posX = posY = 0;
    angle = 0;
    maxVelocity = 1.0f + r.nextFloat() * 2;
    velocity = 1.0f + r.nextFloat();
    pathIdx = 0;
    routeIdx = 0;
    ID = ++nrID;
    red = r.nextInt(255);
    green = r.nextInt(255);
    blue = r.nextInt(255);
  }

  public List<RoadEdge> getRoute() {
    return route;
  }

  public void setRoute(List<RoadEdge> route) {
    List<RoadEdge> newRoute = new ArrayList<RoadEdge>();
    newRoute.add(route.get(0));
    for (int i = 1; i < route.size() - 1; i++) {
      RoadEdge prev = route.get(i);
      RoadEdge next = route.get(i + 1);
      if (!(prev.getTo().getX() == next.getFrom().getX() && prev.getTo()
        .getY() == next.getFrom().getY())) {
        RoadEdge reversed = new RoadEdge(p, next.getTo(), 
        next.getFrom());
        newRoute.add(reversed);
      } 
      else {
        RoadEdge oriented = new RoadEdge(p, next.getFrom(), 
        next.getTo());
        newRoute.add(oriented);
      }
    }
    this.route = newRoute;
    if (newRoute.size() == 0) p.println ("size = 0");
    this.setRoad(newRoute.get(0));
    routeIdx = 0;
    // debug
    // p.println (ID);
    // for (RoadEdge r : newRoute) {
    // p.println(r.getID());
    // p.println(r.getFrom().getX() + " " + r.getFrom().getY());
    // p.println(r.getTo().getX() + " " + r.getTo().getY());
    // p.println("----\n");
    // }
  }

  public int getID() {
    return ID;
  }

  public float getMaxVelocity() {
    return maxVelocity;
  }

  public void setMaxVelocity(float maxVelocity) {
    this.maxVelocity = maxVelocity;
  }

  public float getVelocity() {
    return velocity;
  }

  public void setVelocity(float velocity) {
    this.velocity = velocity;
  }

  public void incVelocity() {
    velocity = velocity + 0.1f;
  }

  public void decVelocity() {
    velocity = velocity - 0.05f;
  }

  public float getPathIdx() {
    return pathIdx;
  }

  public void setPathIdx(float pathIdx) {
    this.pathIdx = pathIdx;
  }

  public void draw() {
    p.fill(red, green, blue);
    p.stroke(red, green, blue);
    p.rectMode(p.CENTER);
    // p.rect(posX, posY, 2, 2);
    // p.text(ID, posX, posY);
    p.pushMatrix();
    p.translate(posX+2, posY+2, 2);
    p.box(4);
    p.popMatrix();
    p.fill(255);
    p.stroke(255);
    //		for (RoadEdge segment : route) {
    //			segment.drawDebug();
    //		}
  }

  public boolean update() { // todo: pathidx +/- glede na smer
    boolean result = false;
    if (!this.isAtEnd()) {
      float[] coords = (float[]) road.getPathPositions().get(
      (int) pathIdx);
      posX = coords[0];
      posY = coords[1];
      pathIdx += velocity;
    } 
    else {
      if (!isAtEndOfRoute()) {
        routeIdx++;
        RoadEdge nextRoad = route.get(routeIdx);
        this.setRoad(nextRoad);
      }
      else result = true;
    }
    return result;
  }

  public boolean isAtEnd() { // todo: še za 0
    if (pathIdx >= road.getPathPositions().size())
      return true;
    else
      return false;
  }

  public boolean isAtEndOfRoute() {
    if (route.get(route.size() - 1).equals(road) && this.isAtEnd()) {
      return true;
    } 
    else
      return false;
  }

  public RoadEdge getRoad() {
    return road;
  }

  public void setRoad(RoadEdge road) { // todo: pathidx = 1
    this.road = road;
    pathIdx = 0;
    posX = road.getFrom().getX();
    posY = road.getFrom().getY();
  }

  public float getPosX() {
    return posX;
  }

  public void setPosX(float posX) {
    this.posX = posX;
  }

  public float getPosY() {
    return posY;
  }

  public void setPosY(float posY) {
    this.posY = posY;
  }

  public float getAngle() {
    return angle;
  }

  public void setAngle(float angle) {
    this.angle = angle;
  }
}

