package cz.cuni.amis.pogamut.ut2004.agent.navigation;

import cz.cuni.amis.pogamut.base.agent.navigation.AbstractPathPlanner;
import cz.cuni.amis.pogamut.base.agent.navigation.PathNotConstructable;
import cz.cuni.amis.pogamut.base.agent.worldview.IWorldView;
import cz.cuni.amis.pogamut.base.agent.worldview.WorldEventListener;
import cz.cuni.amis.pogamut.base.communication.commands.IAct;
import cz.cuni.amis.pogamut.base.communication.exceptions.CommunicationException;
import cz.cuni.amis.pogamut.base3d.worldview.objects.ILocated;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.GetPath;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PathList;
import cz.cuni.amis.pogamut.ut2004.communication.translator.events.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Finds the shortest through internal A* algorithm in the UT2004. The path info
 * is send through Gamebots messages.
 * @author Ik
 */
public class UTAstar extends AbstractPathPlanner<ILocated, ILocated> {

    /**
     * Serializer is used to send the path request to the GB. 
     */
    IAct commandSerializer = null;
    IWorldView worldView = null;
    String lastPathRequestID = null;
    WorldEventListener<Path> pathReceivedListener = null;

    public UTAstar(IAct commandSerializer, IWorldView worldView) {
        this.commandSerializer = commandSerializer;
        this.worldView = worldView;
    }

    /**
     * Resends the path request to the GB.
     * @param from
     * @param to
     * @return
     * @throws cz.cuni.amis.pogamut.base.agent.navigation.PathNotConstructable
     */
    public List<ILocated> computePath(ILocated from, ILocated to) throws PathNotConstructable {
        try {
            // stop listening for last path request if there was any
            if (pathReceivedListener != null) {
                worldView.removeListener(Path.class, pathReceivedListener);
            }

            // add listener for the request response
            pathReceivedListener = new WorldEventListener<Path>() {

                public void notify(Path event) {
                    if (event.getPathId().equals(lastPathRequestID)) {
                        firePathEvent(translatePath(event));
                        // we are done
                        worldView.removeListener(Path.class, this);
                    }
                }
            };

            worldView.addListener(Path.class, pathReceivedListener);
            // send the request
            lastPathRequestID = UUID.randomUUID().toString();
            commandSerializer.act(new GetPath(lastPathRequestID, to.getLocation()));
            // TODO aproximate path
            return null;
        } catch (CommunicationException ex) {
            throw new PathNotConstructable("Path request not send because of communication exception.", ex);
        }
    }

    /**
     * Translates the path from GB Path object to list of navpoints.
     * @param path
     * @return
     */
    protected List<ILocated> translatePath(Path path) {
        List<ILocated> translated = new ArrayList<ILocated>();
        for (PathList pathElem : path.getPath()) {
            translated.add(worldView.getAll(NavPoint.class).get(pathElem.getRouteId()));
        }
        return translated;
    }
}
