import threading
import time

from test.urlloader import URLLoader

from engine import Engine
from game import Game, Sprite
from command import Command

class config:
    host = ''
    port = 8083
    framerate = 50
    timeout = 5.0
    max_events_per_request = 2000
    max_events_in_buffer = 100

class UserControlledObject(Sprite):
    speed = 300
    maxtop = 500
    maxleft = 700

    def calculate_state(self, framestates, timespent):
        super(UserControlledObject, self).calculate_state(framestates,
                                                          timespent)
        fs = framestates[self.id]
        for command, value in fs.unknown:
            self.commands.put((self.id, Command(command, value)))
        else:
            for i in range(10): # is 10 commands per loop somewhat expected?
                self.commands.put((self.id, Command('AA', i)))

class TestGame(Game):
    def add_user(self, userid):
        self.add_sprite(UserControlledObject(userid, self))

    def del_user(self, userid):
        self.del_sprite(userid)

class Client(object):
    def __init__(self, config):
        self.config = config
        self.out = out = URLLoader(config, '/out')
        self.out.initialize()
        headers = out.headers()
        assert '200' in headers[0]
        self.id = id = out.next_line().strip()
        print 'client %s initialized' % (id,)

        self.index = 0
        self.failed_loads = 0
        self.failed_ids = 0

    def next(self):
        self.index += 1
        inchan = URLLoader(self.config, '/in',
                           '%s\r\nCC%s\r\n' % (self.id, self.index))
        inchan.initialize()
        headers = inchan.headers()
        inchan.close()
        if not '200' in headers[0] and not '204' in headers[0]:
            # print headers
            self.failed_loads += 1
        else:
            while 1:
                # ignore all commands except CC
                next_line = self.out.next_line()
                if next_line is None:
                    continue
                if ':CC:' in next_line:
                    break
            if next_line.strip() != ':CC:%s' % (self.index,):
                # print '-' * 79
                # print 'expected:', ':CC:%s' % (self.index,)
                # print 'received:', next_line.strip()
                self.failed_ids += 1
                self.index = int(next_line.split(':')[-1])

    def close(self):
        self.out.close()

class EngineRunner(object):
    def __init__(self, config, game):
        self.engine = e = Engine(config, game)
        e.initialize()

    stop = False
    def run(self):
        while not self.stop:
            self.engine.run(count=1)

if __name__ == '__main__':
    import sys
    if len(sys.argv) > 3:
        print 'usage: %s [<numthreads> [<numruns>]]' % (sys.argv[0],)
        sys.exit(1)
    numthreads = 10
    if len(sys.argv) > 1:
        numthreads = int(sys.argv[1])
    numruns = 10
    if len(sys.argv) > 2:
        numruns = int(sys.argv[2])
    print 'number of threads:', numthreads
    print 'number of runs:', numruns
    g = TestGame()
    er = EngineRunner(config, g)
    et = threading.Thread(target=er.run)
    et.start()
    time.sleep(1)
    print 'engine started'
    threads = []
    failed_loads = 0
    failed_ids = 0
    for i in range(numthreads):
        def run(config, i):
            c = Client(config)
            for j in range(numruns):
                time.sleep(0.1)
                c.next()
            c.close()
            print '-' * 79
            print 'client:', i
            print 'failed loads:', c.failed_loads
            print 'failed ids:', c.failed_ids
        t = threading.Thread(target=run, args=(config, i))
        t.start()
        threads.append(t)
        print 'started thread', i
        time.sleep(0.1)
    for t in threads:
        t.join()
    er.stop = True
    et.join()
    er.engine.close()
    print '-' * 79
    print 'total failed loads:', failed_loads
    print 'total failed ids:', failed_ids


