// SampleBot, a sample bot using the SkeletonBot framework.
// Public domain.

package edu.bowdoin.gamebots;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;

import edu.bowdoin.gamebots.SkeletonBot;
import edu.isi.gamebots.client.Message;
import edu.isi.gamebots.examples.Vector3D;

/**
 * SampleBot demonstrates usage of the SkeletonBot framework.  It runs randomly
 * from navigation node to navigation node and is easily confused.
 *
 * @author Alec Berryman &lt;<a href="mailto:aberryma@bowdoin.edu">aberryma@bowdoin.edu</a>&gt;
 */
public class SampleBot extends SkeletonBot {
    // Nav node structures
    private final Object nav_mutex = new Object(); // mutex
    private HashMap<String, Vector3D> nodes = new HashMap(); // reachable nodes

    // Target node
    private String target_id; // target node ID
    private Vector3D target_loc; // target location

    // Random generator for picking next target
    private final Random r = new Random();

    /**
     * Bot decision control.  If we're not close to the target navigation node,
     * keep going until we get there.  If we're at the target navigation node,
     * pick another one.
     */
    protected void decider() {
        synchronized(nav_mutex) {
            if (target_id == null || target_loc.near(get_location(), PLAYER_RADIUS)) {
                // We're close to the target node or we don't have a target.
                Object[] targets = nodes.keySet().toArray();
                if (targets.length < 1) {
                    // Need at least one possible target.
                    return;
                } else {
                    // Pick a random target.
                    target_id = (String) targets[r.nextInt(targets.length)];
                    target_loc = nodes.get(target_id);
                    send_runto(target_loc);
                }
            }
            log.logNote("Current target: " + target_id);
        }
    }

    /**
     * Add all reachable navigation nodes to our list of places to go.
     */
    protected void handle_nav(Message m) {
        String id = m.getProperty(ACTOR_ID);
        String reachable = m.getProperty(ACTOR_REACHABLE);

        if (reachable.equals(FALSE)) {
            // We can't get there from here.  Remove it from the list of
            // reachable nodes.
            synchronized(nav_mutex) {
                nodes.remove(id);
            }
        } else {
            // We can get there from here!  Add it to the list of reachable
            // nodes.
            String loc_s = m.getProperty(LOCATION);
            Vector3D loc_v;

            try {
                double[] loc_d = parseVector(loc_s);
                loc_v = new Vector3D(loc_d[0], loc_d[1], loc_d[2]);
            } catch(NumberFormatException e) {
                // If there was an error, we didn't want to go there, anyway.
                return;
            }

            synchronized(nav_mutex) {
                nodes.put(id, loc_v);
            }
        }
    }

    /**
     * Reset reachable nodes on death.
     */
    protected void handle_die(Message m) {
        synchronized(nav_mutex) {
            nodes.clear();
            target_id = null;
            target_loc = null;
        }
    }
}

