#!/usr/bin/python

import Tkinter, random, Pmw, os, copy, re, pprint, tkFileDialog
Tk = Tkinter

################################################################################

margin = 40

tick = 1000   # ms

zoom = 0.5
radius = 4
pause = 0
increment = 1
callback = None

cluster = 0    # dis/en-able partioning code
if cluster:
	from clason import calculate_partition

################################################################################

def read_position_data(datafile):
	global data, map_x0, map_y0, map_x1, map_y1, map_width, map_height, frames

	file = open( datafile )

	data = []

	currentTimeDictionary = {}

	map_name = file.readline();
	map_type = file.readline();
	map_display_name = file.readline();
	map_display_type = file.readline();
	map_x0, map_y0, map_width, map_height = map(float, file.readline().split())
	map_x1, map_y1 = map_x0 + map_width, map_y0 + map_height
	map_y0, map_y1 = -map_y1, -map_y0

	root.title("%s (%s)" % (map_display_name, map_display_type))

	l = file.readline()
	while l != "\n" and l != "\r\n":
		l = l.strip("\r\n")
		team, type, block, name, x, y, z, desc = l.split(' ', 7)
		team, x, y, z = int(team), float(x), float(y), float(z)
		if type in ('SpawnSphere', 'InteriorInstance', 'AIObjective'):
			pass
		else:
			if type == 'WayPoint':
				map_item.append([x, -y, z, team, desc])
			elif (type, block[:9]) == ('StaticShape', 'Generator'):
				map_item.append([x, -y, z, team, 'G'])
			elif (type, block) == ('StaticShape', 'StationInventory'):
				map_item.append([x, -y, z, team, 'I'])
			elif (type, block) == ('StaticShape', 'StationVehiclePad'):
				map_item.append([x, -y, z, team, 'V'])
			elif type == 'Turret':
				map_item.append([x, -y, z, team, 'T'])
			elif (type, block[:6]) == ('StaticShape', 'Sensor'):
				map_item.append([x, -y, z, team, 'S'])

		l = file.readline()

	carrier = []
	l = file.readline()
	while l != '':
		if l == "\n" or l == "\r\n":
			data.append( currentTimeDictionary )
			currentTimeDictionary = {}
			carrier = []
		else:
			m = l.strip().split(' ', 5)  # the file format is: "playerid team x y z name"
			playerID = m.pop(0)
			if playerID == 'flag':
				if len(m) == 2:
					# the flag is being carried
					carrier.append(m[1])
				else:
					m.append('flag')
					playerID += m[0]
	
			if len(m) == 5 and m[1] != '':
				team = int(m[0])
				x = float(m[1])
				y = -float(m[2])
				z = float(m[3])
				name = m[4]

				currentTimeDictionary[playerID] = x, y, z, team, name, playerID in carrier


		l = file.readline()

	frames = len(data)
	print frames, "frames"

################################################################################


def move_to(time):
	global actor, data
	
	actor1 = {}

	nowData = data[time]

	for clientID in nowData.keys():
		x, y, z, team, name, flag = nowData[clientID]
		x = (x - map_x0) * zoom
		y = (y - map_y0) * zoom
		colour = ('black', 'green', 'red')[team]

		if flag:
			colour, bcolour = 'black', colour
			rad = radius * 2
		else:
			bcolour = 'black'
			rad = radius

		if actor.has_key( clientID ):
			dot, label = actor[clientID]
			del actor[clientID]
			canvas.coords(dot, x - rad, y - rad, x + rad, y + rad)
			canvas.coords(label, x, y)
			canvas.itemconfigure(dot, fill=colour, outline=bcolour)

		else:
			if team == 1:
				dot = canvas.create_oval(x - rad, y - rad,
						x + rad, y + rad, fill=colour, outline=bcolour)
			else:
				dot = canvas.create_rectangle(x - rad, y - rad,
						x + rad, y + rad, fill=colour, outline=bcolour)
			label = canvas.create_text(x, y, text=name)

		actor1[clientID] = (dot, label)

	# any dot left is dead or has left the game, so remove it
	for dot, label in actor.values():
		 canvas.delete(dot)
		 canvas.delete(label)

	actor = actor1

	if cluster:
		show_partition( calculate_partition( data, time, data[time].keys() ) )

	status_bar.configure(text='%i / %i, zoom %.2f' % (time+1, frames, zoom))


def move():
	global time, pause, increment, callback, current_partition, current_partition_cost, SWITCH_MULTIPLIER

	callback = None

	if increment > 0 and time == frames - 1:
		return
	elif increment < 0 and time == 0:
		return

	time += increment
	move_to(time)

	callback = root.after(int(tick), move)





def show_partition( partition ):
	global rectangle

	for rect in rectangle:
		canvas.delete(rect)

	rectangle = []

	for set in partition:
		x0, y0, x1, y1 = 1e10, 1e10, -1e10, -1e10
		for player in set:
			x0 = min((x0, data[time][player][0]))
			y0 = min((y0, data[time][player][1]))
			x1 = max((x1, data[time][player][0]))
			y1 = max((y1, data[time][player][1]))
		rectangle.append(canvas.create_rectangle((x0 - map_x0) * zoom, (y0 - map_y0) * zoom,
							 (x1 - map_x0) * zoom, (y1 - map_y0) * zoom))



################################################################################

def zoom_in(event):
	global zoom
	zoom = zoom * 1.2
	update_zoom()

def zoom_out(event):
	global zoom
	zoom = zoom / 1.2
	update_zoom()

def update_zoom():
	canvas.coords(bg_rect, 0, 0, map_width * zoom, map_height * zoom)
	for item in map_item:
		x, y, z, team, name, label = item
		x = (x - map_x0) * zoom
		y = (y - map_y0) * zoom
		canvas.coords(label, x, y)
	canvas.resizescrollregion()
	move_to(time)

def unpause():
	global pause
	if pause == 0:
		return
	pause = 0
	move()

def setpause():
	global pause, callback
	if pause == 1:
		return
	pause = 1
	if callback is not None:
		root.after_cancel(callback)
		callback = None

def button_handler(event):
	global pause, increment, time, tick, partition_index

	if event == '|<':
		setpause()
		time = 0
		move_to(time)
		increment = 1
		tick = 1000
	elif event == '<':
		unpause()
		if increment == 1:
			increment = -1
			tick = 1000
		else:
			tick = tick * 0.8
	elif event == '||<':
		setpause()
		if time > 0:
			time -= 1
		move_to(time)
	elif event == '||':
		if pause:
			unpause()
		else:
			setpause()
	elif event == '>||':
		setpause()
		if time < frames - 1:
			time += 1
		move_to(time)
	elif event == '>':
		unpause()
		if increment == -1:
			increment = 1
			tick = 1000
		else:
			tick = tick * 0.8
	elif event == '>|':
		setpause()
		time = frames - 1
		move_to(time)
		increment = -1
		tick = 1000
	elif event == 'partition':
		show_partition( calculate_partition(data, time, data[time].keys()) )

		


############################################################################### 

root = Tk.Tk()
root.withdraw()
Pmw.initialise()

actor = {}
map_item = []
rectangle = []
time = 0

datafile = tkFileDialog.askopenfilename()

read_position_data(datafile)

toolbar = Tk.Frame(root)

button = {}
event_list = ['|<', '<', '||<', '||', '>||', '>', '>|']
if cluster:
	event_list += ['partition']
for event in event_list:
	button[event] = Tk.Button(toolbar, text=event, command=lambda x=event: button_handler(x))
	button[event].pack(side=Tk.LEFT, anchor=Tk.W)

status_bar = Tk.Label(toolbar, text='')
status_bar.pack(side=Tk.LEFT, anchor=Tk.W)

toolbar.pack(side=Tk.TOP, anchor=Tk.W)

canvas = Pmw.ScrolledCanvas(root,
			    hull_width=5000,
			    hull_height=5000,
			    usehullsize=1,
			    canvasmargin=margin)
bg_rect = canvas.create_rectangle(0, 0, map_width * zoom, map_height * zoom,
			  outline='black', fill='white')
	
for item in map_item:
	x, y, z, team, name = item
	x = (x - map_x0) * zoom
	y = (y - map_y0) * zoom
	colour = ('black', 'darkgreen', 'red')[team]
	label = canvas.create_text(x, y, text=name, fill=colour)
	item.append(label)

canvas.pack(side=Tk.TOP)
canvas.resizescrollregion()

Tk.Widget.bind(canvas.component('canvas'), '<Button-1>', zoom_in)
Tk.Widget.bind(canvas.component('canvas'), '<Button-3>', zoom_out)

move()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry('=%ix%i+%i+%i' % (w * 0.8, h * 0.8, w * 0.1, h * 0.1))
root.wm_deiconify()

root.mainloop()

