from collections import namedtuple

WireInGrid = namedtuple('WireInGrid', 'tile grid_x grid_y wire')
Connection = namedtuple('Connection', 'wire_a wire_b')


class Connections(object):
    def __init__(self, tilegrid, tileconn, tile_wires):
        self.grid = tilegrid
        self.tile_wires = tile_wires
        self.coord_to_tile = {}
        self.coord_to_tile_type = {}

        for tile, tile_info in self.grid.items():
            self.coord_to_tile[(tile_info['grid_x'],
                                tile_info['grid_y'])] = tile
            self.coord_to_tile_type[(tile_info['grid_x'],
                                     tile_info['grid_y'])] = tile_info['type']

            # Make sure we have tile type info for every tile in the grid.
            assert tile_info['type'] in self.tile_wires, (
                tile_info['type'], self.tile_wires.keys())

        self.potential_connections = {}

        for conn in tileconn:
            grid_deltas = conn['grid_deltas']
            tile_types = conn['tile_types']

            for pairs in conn['wire_pairs']:
                key = (tile_types[0], pairs[0])
                if key not in self.potential_connections:
                    self.potential_connections[key] = []
                self.potential_connections[key].append(
                    (grid_deltas, tile_types[1], pairs[1]))

    def all_possible_connections_from(self, wire_in_grid):
        tile_type = self.coord_to_tile_type[(wire_in_grid.grid_x,
                                             wire_in_grid.grid_y)]

        key = (tile_type, wire_in_grid.wire)

        if key not in self.potential_connections:
            return

        for relative_coord, target_tile_type, target_wire in (
                self.potential_connections[key]):
            rel_x, rel_y = relative_coord
            target_coord = (wire_in_grid.grid_x + rel_x,
                            wire_in_grid.grid_y + rel_y)

            if target_coord in self.coord_to_tile_type:
                if self.coord_to_tile_type[target_coord] == target_tile_type:
                    yield Connection(
                        wire_in_grid,
                        WireInGrid(
                            tile=self.coord_to_tile[target_coord],
                            grid_x=target_coord[0],
                            grid_y=target_coord[1],
                            wire=target_wire))

    def get_connections(self):
        """ Yields Connection objects that represent all connections present in
    the grid based on tileconn """
        for tile, tile_info in self.grid.items():
            for wire in self.tile_wires[tile_info['type']]:
                wire_in_grid = WireInGrid(
                    tile=tile,
                    grid_x=tile_info['grid_x'],
                    grid_y=tile_info['grid_y'],
                    wire=wire)
                for potential_connection in self.all_possible_connections_from(
                        wire_in_grid):
                    yield potential_connection
