import java.util.*;

public class Player extends Robot {
  private static String MOVE = "Move";
  private static String PICK = "Pick";
  private static String DROP = "Drop";
  
  private int capacity;
  private int money;
  private ArrayList path;
  private ArrayList myPackages;

  public Player(int id, int capacity, int money, Environment env) {
    super(id, env);
    this.capacity = capacity;
    this.money = money;
    myPackages = new ArrayList();
  }

  public int getCapacity() {
    return capacity;
  }

  protected void setCapacity(int capacity) {
    this.capacity = capacity;
  }

  public int getMoney() {
    return money;
  }

  protected void setMoney(int money) {
    this.money = money;
  }

  public String move(String packages) {
    System.out.println(packages);
    // Drop any packages
    Iterator iter = getPackageList().iterator();
    Package current;
    String ids = "";
    while (iter.hasNext()) {
      current = (Package) iter.next();
      if (current != null && current.getDestX() == getX()
      && current.getDestY() == getY()) {
        ids += " " + current.getId();
      }
    }
    if (!"".equals(ids)) {
      path = null;
      money--;
      return "1 " + DROP + ids;
    }

    // parse the package list and pick up any
    if (!"".equals(packages)) {
      StringTokenizer st = new StringTokenizer(packages);
      ArrayList packageList = new ArrayList();
      Package p;
      while (st.hasMoreTokens()) {
        p = new Package(Integer.parseInt(st.nextToken()), getX(), getY(),
	  getEnvironment());
	p.setDestX(Integer.parseInt(st.nextToken()));
	p.setDestY(Integer.parseInt(st.nextToken()));
	p.setWeight(Integer.parseInt(st.nextToken()));
	packageList.add(p);
	if (!myPackages.contains(p)) {
	  myPackages.add(p);
	}
      }
      boolean full = false;
      int availiable = getAvailiableCapacity();
      int largest;
      ids = "";
      while (!full && availiable > 0) {
	iter = packageList.iterator();
	largest = 0;
	p = null;
	while (iter.hasNext()) {
	  current = (Package) iter.next();
	  if (current.getWeight() > largest
	  && availiable - current.getWeight() >= 0) {
	    largest = current.getWeight();
	    p = current;
	  }
	}
	if (p != null) {
	  ids += " " + p.getId();
	  availiable -= p.getWeight();
	  packageList.remove(packageList.indexOf(p));
	} else {
	  full = true;
	}
      }
      if (!"".equals(ids)) {
        path = null;
	money--;
        return "1 " + PICK + ids;
      }
    } else {
      getEnvironment().setCondition(getX(), getY(), Environment.EMPTY);
    }
    
    // Move towards the best goal
    if (path == null || !((Node) path.get(path.size() - 1)).equals(getNode()))
      path = findRoute(findGoal());
    path.remove(path.size() - 1);
    money--;
    return "1 " + MOVE + ' ' + getDirectionTo((Node) path.get(path.size() - 1));
  }

  private char getDirectionTo(Node n) {
    System.out.println("to " + n.getX() + ' ' + n.getY());
    if (n.getX() > getX())
      return 'E';
    if (n.getX() < getX())
      return 'W';
    if (n.getY() > getY())
      return 'N';
    return 'S';
  }
  
  public void pickUp(Package p) {
    super.pickUp((Package) myPackages.get(myPackages.indexOf(p)));
  }

  private int getAvailiableCapacity() {
    int result = getCapacity();
    Iterator iter = getPackageList().iterator();
    int weight;
    while (iter.hasNext()) {
      weight = ((Package) iter.next()).getWeight();
      result -= weight;
    }
    return result;
  }

  private Node findGoal() {
    Iterator iter = getPackageList().iterator();
    HashMap dests = new HashMap();
    Package p;
    Node n;
    Node result = null;
    int best = -1;
    int weight;
    System.out.println("finding destination");
    while (iter.hasNext()) {
      p = (Package) iter.next();
      n = p.getDestinationNode();
      weight = dests.containsKey(n) ? ((Integer) dests.get(n)).intValue() : 0;
      weight += p.getWeight();
      if (weight > best) {
        best = weight;
	result = n;
      }
      dests.put(n, new Integer(weight));
    }
    if (result == null) {
      System.out.println("finding goal");
      result = findClosest(Environment.BASE);
    }
    if (result == null) {
      System.out.println("finding dropped");
      result = findClosest(Environment.DROPPED);
    }
    if (result == null) {
      ArrayList foo =
        (new Node(getX(), getY(), getEnvironment())).getSuccessors();
      result = (Node) foo.get((new Random()).nextInt(foo.size()));
    }
    System.out.println("destination = " + result.getX() + ", " + result.getY());
    return result;
  }

  private ArrayList findRoute(Node goal) {
    Node start = getNode();
    Node current = null, temp;
    ArrayList open = new ArrayList();
    ArrayList closed = new ArrayList();
    int low, index;
    Iterator iter;
    open.add(start);
    while (!open.isEmpty()) {
      iter = open.iterator();
      current = (Node) iter.next();
      low = current.distanceTo(goal);
      while (iter.hasNext()) {
        temp = (Node) iter.next();
	if (temp.getScore() < low) {
	  current = temp;
	  low = current.distanceTo(goal);
	}
      }
      if (current.equals(goal)) {
        ArrayList result = new ArrayList();
	while (current.hasParent()) {
	  System.out.println("" + current.getX() + ' ' + current.getY());
	  result.add(current);
	  current = current.getParent();
	}
	result.add(current);
        return result;
      }
      iter = current.getSuccessors().iterator();
      while (iter.hasNext()) {
        temp = (Node) iter.next();
	if (open.contains(temp)) {
	  index = open.indexOf(temp);
	  if (((Node) open.get(index)).getScore() < temp.getScore())
	    continue;
	  open.remove(index);
	}
	if (closed.contains(temp)) {
	  index = closed.indexOf(temp);
	  if (((Node) closed.get(index)).getScore() < temp.getScore())
	    continue;
	  closed.remove(index);
	}
	open.add(temp);
      }
      open.remove(open.indexOf(current));
      closed.add(current);
    }
    return new ArrayList();
  }

  private Node findClosest(char type) {
    Node result = null;
    Node n;
    int current;
    int best = Integer.MAX_VALUE;
    Iterator iter = getEnvironment().listType(type).iterator();
    while (iter.hasNext()) {
      n = (Node) iter.next();
      current = Math.abs(getX() - n.getX()) + Math.abs(getY() - n.getY());
      if (current < best) {
	best = current;
	result = n;
      }
    }
    return result;
  }
}
