#!/bin/env python
# Python solution to mamund's maze problem (functional style)
# see http://amundsen.com/examples/misc/maze-client.html

from xml.etree.ElementTree import XML
from httplib2 import Http

MAZE = "http://amundsen.com/examples/mazes/2d/five-by-five/"
RULES = {
    'east'  : ['south','east','north','west'],
    'south' : ['west','south','east','north'],
    'west'  : ['north','west','south','east'],
    'north' : ['east','north','west','south']
}

def get(uri):
    """ return the XML from the given uri """
    resp, content = Http().request(
                      uri,
                      headers={
                        'Accept':
                          "application/vnd.amundsen.maze+xml"})
    return XML(content)

def get_links(uri):
    """ 
    return a dict {rel: href} of the <link>s found at the given uri
    """
    return dict(
         (link.get('rel'), link.get('href')) 
         for link in get(uri).findall('*/link')
        )

def selector(rules):
    """
    a little closure to create the next-link selector based on the 
    given rules
    """
    def select(facing, links):
        """
        app logic:
        given the current facing direction and the available links,
        chooses the next direction (according to the rules),
        follows the link and return the new facing direction and the 
        available links for the current state
        """
        if facing is None and 'start' in links:
            return ('north', get_links(links['start']))
        if 'exit' in links:
            return ('exit', get_links(links['exit']))
        for choice in rules[facing]:
            if choice in links:
                return (choice, get_links(links[choice]))
    return select

def find_path(maze, rules):
    """ 
    just follow the links until exit, yielding the current state 
    """
    select_next = selector(rules)
    facing, links = None, get_links(maze)
    while facing is not 'exit':
        facing, links = select_next(facing, links)
        yield (facing, links)

if __name__ == '__main__':
    import sys
    if len(sys.argv) == 2:
        maze = sys.argv[1]
    else:
        maze = MAZE
    for step, (facing, links) in enumerate(find_path(maze, RULES)):
        print "%s: go to %s"  % (step, facing)
        print "    <%s>" % (links.get('current', ''),)
    print "I'm free !"

