package ch.zhaw.ads;

import java.awt.Color;

public class LabyrinthServer implements CommandExecutor {
    final double SCALE = 10;

    private ServerGraphics serverGraphics;
    Graph<LabyrinthNode, Edge> graph;

    @Override
    public String execute(String command) {
        serverGraphics = new ServerGraphics();
        graph = new AdjListGraph<LabyrinthNode, Edge>(LabyrinthNode.class, Edge.class);

        serverGraphics.clear();
        serverGraphics.setColor(Color.BLACK);
        serverGraphics.fillRect(0, 0, 1, 1);

        // read in data
        for (String record : command.split("\\r?\\n")) {
            String[] values = record.split(" ");

            try {
                graph.addEdge(values[0], values[1], 0.0);
                graph.addEdge(values[1], values[0], 0.0);
            } catch (Throwable e) {
                e.printStackTrace();
            }

            this.drawPath(serverGraphics, values[0], values[1], false);
        }


        // find path
        // start and goal are taken from the picture in the exercise
        LabyrinthNode<Edge> start = graph.findNode("0-6");
        LabyrinthNode<Edge> goal = graph.findNode("3-0");
        this.unmarkAll();
        if (this.search(start, goal)) {
            LabyrinthNode<Edge> current = goal;
            while (current.getPrev() != null) {
                LabyrinthNode<Edge> prev = current.getPrev();
                this.drawPath(serverGraphics, current.getName(), prev.getName(), true);
                current = prev;
            }
        } else {
            System.out.println("Failed to find path.");
        }

        return serverGraphics.getTrace();
    }


    private void unmarkAll() {
        for (LabyrinthNode<Edge> node : graph.getNodes()) {
            node.setMark(false);
            node.setPrev(null);
        }
    }


    private boolean search(LabyrinthNode<Edge> currentNode, LabyrinthNode<Edge> goal) {
        currentNode.setMark(true);

        if (currentNode.equals(goal)) return true;

        for (Edge<LabyrinthNode> edge : currentNode.getEdges()) {
            LabyrinthNode<Edge> sucessor = edge.getDest();
            if (!sucessor.getMark()) {
                if (this.search(sucessor, goal)) {
                    sucessor.setPrev(currentNode);
                    return true;
                }
            }
        }
        currentNode.setMark(false);
        return false;
    }


    private void drawPath(ServerGraphics g, String from, String to, boolean mouse) {
        if (mouse) serverGraphics.setColor(Color.RED);
        else serverGraphics.setColor(Color.WHITE);
        double scale = 10;
        double xh0 = from.charAt(0) - '0';
        double yh0 = from.charAt(2) - '0';
        double xh1 = to.charAt(0) - '0';
        double yh1 = to.charAt(2) - '0';
        double x0 = Math.min(xh0,xh1)/SCALE;
        double y0 = Math.min(yh0,yh1)/SCALE;
        double x1 = Math.max(xh0,xh1)/SCALE;
        double y1 = Math.max(yh0,yh1)/SCALE;
        double w = 1/SCALE;
        if (mouse) g.drawLine(x0+w/2,y0+w/2,x1+w/2,y1+w/2);
        else {
            if (y0 == y1)
                g.fillRect(x0,y0,x1-x0+w,w);
            else
                g.fillRect(x0,y0,w,y1-y0+w);
        }
    }
}
