import socket, sys, json, threading, time
import Tkinter as tk
from particle_interaction import *

HOST, PORT = "127.0.0.1", 9999

end='\n'
def recv_end(the_socket):
    total_data = []
    data = ''
    while True:
            data = the_socket.recv(8192)
            if end in data:
                total_data.append(data[:data.find(end)])
                break
            total_data.append(data)
            if len(total_data) > 1:
                # check if end_of_data was split
                last_pair = total_data[-2] + total_data[-1]
                if end in last_pair:
                    total_data[-2]=last_pair[:last_pair.find(end)]
                    total_data.pop()
                    break
    return ''.join(total_data)

class Root(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.curr_time = 0
        self.real_time = time.time()
        self.msg_queue = []
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((HOST, PORT))
        self.after(5, self.check_msg_queue)
        ServerThread(self.msg_queue, self.sock).start()
    
    def set_sim(self, sim):
        self.sim = sim
    
    def check_msg_queue(self):
        while self.msg_queue:
            self.handle_message(self.msg_queue.pop())
        self.after(5, self.check_msg_queue)
        
    def handle_message(self, msg):
        self.sim.realtime_interrupt(msg)
    
    def send_msg(self, msg):
        try:
            self.sock.send(msg + '\n')
        except socket.error:
            self.quit()
        
    def handle_output_pos(self, msgs):
        for msg_contents in msgs:
            self.send_msg(json.dumps(["POS_OUT", msg_contents]))
    
    def handle_output_color(self, msgs):
        for msg_contents in msgs:
            self.send_msg(json.dumps(["COLOR_OUT", msg_contents]))
    
    def handle_output_time(self, msgs):
        real_time = time.time()
        self.curr_time += real_time - self.real_time
        self.real_time = real_time
        for msg_contents in msgs:
            if (self.curr_time) - msg_contents / 30.0 > 0.05:
                print 'running behind! %s' % ((self.curr_time) - msg_contents / 30.0)
            self.send_msg(json.dumps(["TIME_OUT", "%.2f" % (float(msg_contents / 30.0))]))
            
class ServerThread(threading.Thread):
    def __init__(self, queue, serversocket):
        threading.Thread.__init__(self)
        self.daemon = True
        self.queue = queue
        self.serversocket = serversocket
    
    def run(self):
        end = '\n'
        total_data = []
        while 1:
            try:
                data = self.serversocket.recv(8192)
            except socket.error:
                break
            if end in data:
                total_data.append(data[:data.find(end)])
                self.queue.append(''.join(total_data))
                total_data = []
            else:
                total_data.append(data)
                if len(total_data) > 1:
                    # check if end_of_data was split
                    last_pair = total_data[-2] + total_data[-1]
                    if end in last_pair:
                        total_data[-2]=last_pair[:last_pair.find(end)]
                        total_data.pop()
                        self.queue.append(''.join(total_data))

if __name__ == '__main__':
    resolution = (800, 600)
    framerate = 30
    spawn_chance = 0.2
    die_chance = 0.01
    
    root = Root()
    root.withdraw()

    model = Field(Canvas(resolution), framerate, spawn_chance, die_chance)    
    sim = Simulator(model)
    root.set_sim(sim)
    sim.setRealTime(True, 1.0 / framerate)
    sim.setRealTimeInputFile(None)
    sim.setRealTimePorts({'INTERRUPT': model.INTERRUPT})
    sim.setRealTimePlatformTk(root)
    sim.setDSDEVS(True)
    sim.setClassicDEVS(True)
    sim.setTerminationTime(60 * framerate)
    
    sim.setListenPorts(model.POS_OUT, root.handle_output_pos)
    sim.setListenPorts(model.COLOR_OUT, root.handle_output_color)
    sim.setListenPorts(model.TIME_OUT, root.handle_output_time)
    
    sim.simulate()
    root.mainloop()