class Controller:
    def __init__(self, connection):
        self._connection = connection
        self._engine = Engine()
        self._cmd_timestamps = deque([0] * 9, 5) # max 9 commands per second
        self._direction = Direction.STOP
        self._score = defaultdict(int)

    def start(self, botname, duelpartner = None):
        log.info("Started controller")
        if duelpartner == None:
            self._join_game(botname)
        else:
            self._request_duel(botname, duelpartner)
        self._mainloop()
        
    def _mainloop(self):   
        response_handlers = {
                'joined': self._game_joined,
                'gameStarted': self._game_started,
                'gameIsOn': self._make_move,
                'gameIsOver': self._game_over
                }
        response = ""
        while True:
            try:
                response = self._connection.receive()
                msg_type, data = response['msgType'], response['data']
                if response_handlers.has_key(msg_type):
                    response_handlers[msg_type](data)
                else:
                    log.warning('Invalid Message received: %s' % response) 
            except:
                log.exception('Json data: %s' % response) 
    
    def _game_joined(self, data):
        log.info('Game visualization url: %s' % data)

    def _game_started(self, data):
        log.info('Game started: %s vs. %s' % (data[0], data[1]))
        self._engine.start_round()

    def _game_over(self, data):
        log.info('Game ended. Winner: %s' % data)
        self._score[data] += 1
        log.info('Score: %s' % self._score)

    def _make_move(self, data):
        dataentry = DataEntry(data)
        direction = self._engine.check_direction(dataentry)   
        self._engine.update(dataentry)
        if direction != self._engine.direction:
            self._set_direction(self._engine.direction)
            
    def _join_game(self, botname):
        log.info('Joining game...')
        self._connection.send({'msgType': 'join', 'data': botname})
        
    def _request_duel(self, botname, duelpartner):
        log.info('Challenging %s...' % duelpartner)
        self._connection.send({'msgType': 'requestDuel', 'data': [botname, duelpartner]})
 
    def _set_direction(self, direction):
        if time.time() - self._cmd_timestamps[0] < Direction.DOWN:
            raise Exception("Discard message. Too many requests sent in one second!")
        self._cmd_timestamps.append(time.time())
        self._connection.send({'msgType': 'changeDir', 'data': direction})