#!/usr/bin/env python3

import sys, socket, time, math

class Vector:
	def __init__(self, x, y):
		self.x, self.y = x, y

	def __repr__(self):
		return '<Vector({x}, {y})>'.format(x = self.x, y = self.y)

	def __add__(self, other):
		return Vector(self.x + other.x, self.y + other.y)

	def __sub__(self, other):
		return Vector(self.x - other.x, self.y - other.y)

	def __mul__(self, other):
		return Vector(self.x * other, self.y * other)

	def __truediv__(self, other):
		return Vector(self.x / other, self.y / other)

	def length(self):
		return math.sqrt(self.x**2 + self.y**2)

	def dot(self, v):
		return self.x*v.x + self.y*v.y

class Cloud:
	def __init__(self, px, py, vx, vy, vapor):
		self.px, self.py, self.vx, self.vy, self.vapor = px, py, vx, vy, vapor
		self.pos = Vector(px, py)
		self.vel = Vector(vx, vy)

	def cloud_repr(self, name):
		return '<{name}({pos}, {vel}, {vapor}>'.format(
				name = name, pos = self.pos,
				vel = self.vel, vapor = self.vapor)

	def get_radius(self):
		return int(math.floor(math.sqrt(self.vapor)))

	def overlap(self, cloud):
		return (self.pos - cloud.pos).length() < self.get_radius() + cloud.get_radius()

	def intersection(self, cloud):
		a = cloud.vel.x * self.vel.x - cloud.vel.y * self.vel.x
		b = cloud.vel.x * (cloud.pos.y - self.pos.y) - cloud.vel.y * (cloud.pos.x - self.pos.x)
		if a == 0 and b == 0:
			print('overlap')
			return True
		elif a != 0:
			v = Vector(self.pos.x + b/a * self.vel.x, self.pos.y + b/a * self.vel.y)
			print('collision:', v)
			return True
		return False

class Thunderstorm(Cloud):
	def __repr__(self):
		return Cloud.cloud_repr(self, 'Thunderstorm')

class Raincloud(Cloud):
	def __repr__(self):
		return Cloud.cloud_repr(self, 'Raincloud')

class State:
	def __init__(self, host, port):
		family = socket.AF_INET
		#if socket.has_ipv6:
		#	family |= socket.AF_INET6
		self.sock = socket.socket(family)
		self.sock.connect((host, port))
		self.s = self.sock.makefile(mode = 'rw', newline = '\n')

	def readline(self):
		return self.s.readline().strip()

	def writeline(self, s):
		self.s.write(s + '\n')
		self.s.flush()

	def read_state(self):
		self.writeline('GET_STATE')
		s = self.readline()
		if not len(s):
			raise Exception('blah')
		you = -1
		storms = []
		clouds = []
		while s != 'END_STATE':
			cmd, data = s.split(None, 1)
			if cmd == 'YOU':
				you = int(data)
			elif cmd == 'THUNDERSTORM':
				storms.append(Thunderstorm(*[float(x) for x in data.split()]))
			elif cmd == 'RAINCLOUD':
				clouds.append(Raincloud(*[float(x) for x in data.split()]))
			s = self.readline()
		self.storms = storms
		self.clouds = clouds
		self.you = you
		self.me = self.storms[you]

	def nearest_cloud(self, v):
		storms = list(self.storms)
		del storms[self.you]
		clouds = self.clouds + storms
		return sorted(clouds, key = lambda c: (c.pos - v).length())

		nearest = -1
		nearest_len = 0
		for i, c in enumerate(self.clouds):
			if nearest == -1 or (c.pos - v).length() < nearest_len:
				nearest = i
				nearest_len = (c.pos - v).length()
		return self.clouds[nearest]

	def wind(self, direction):
		self.writeline('WIND {x} {y}'.format(x = direction.x, y = direction.y))
		print('WIND {x} {y} ({s}, vapor is {v})'.format(x = direction.x, y = direction.y, s = direction.length(), v = self.me.vapor))
		s = self.readline()
		print(s)
		return s == 'OK'

state = State('localhost', 1986)
state.writeline('NAME {0}'.format(sys.argv[0]))
print(state.readline())
print(state.sock.getpeername())

flying = False
dest = Vector(0, 0)

last_dist = 0

def get_vector(dest_cloud, me):
	dest = dest_cloud.pos
	direction = dest - me.pos
	last_dist = direction.length()
	#direction /= direction.length()
	#direction *= 300
	if direction.length() > me.vapor / 2:
		direction /= direction.length()
		direction *= me.vapor / 3
	return direction - me.vel + dest_cloud.vel

while 1:
	start = time.time()
	state.read_state()

	me = state.storms[state.you]
	nearest = state.nearest_cloud(me.pos)
	dest_nearest = state.nearest_cloud(dest)

	if not flying:# or (flying and (dest_nearest[0].pos - me.pos).length() > 100):
		nearest.sort(key = lambda t: math.sqrt(1280**2 + 720**2)-t.vapor)
		vec = Vector(0, 0)
		for dest_cloud in nearest:
			if dest_cloud.vapor > me.vapor - 310:
				continue
			vec = get_vector(dest_cloud, me)
			dest = dest_cloud.pos
			last_dist = (me.pos - dest).length()
			v = dest_cloud.pos - me.pos
			use = True
			# try to avoid collision course with big clouds
			for dc in nearest:
				if dc == dest_cloud:
					continue
				w = dc.pos - me.pos
				pb = me.pos + (v * (w.dot(v) / v.dot(v)))
				if pb.length() <= math.sqrt(me.vapor) + math.sqrt(dc.vapor):
					use = False
					break
			if use:
				print('dest: {0}: {1}, {2}: {3}, dist: {4}'.format(dest, dest_cloud.vapor, me.pos, me.vapor, (me.pos - dest).length()))
				break

		##dest_cloud = nearest[0]
		##dest = dest_cloud.pos
		#me.intersection(dest_cloud)
		# direction to cloud
		##direction = dest - me.pos
		##last_dist = direction.length()
		##direction /= direction.length()
		##direction *= 100

		# TODO: fix
		##temp = dest_cloud.vel * 60
		#temp = Vector(sum([dest_cloud.vel.x * (0.999**i) for i in range(1, 11)]),
				#sum([dest_cloud.vel.y * (0.999**i) for i in range(1, 11)]))
		##print(temp)
		#direction += temp

		#direction /= direction.length() / 120
		# direction we need to fire in
		#real_dir = direction - me.vel
		##real_dir = direction - me.vel
		#real_dir += dest_cloud.vel
		#real_dir /= real_dir.length()
		##strength = real_dir.length()
		#if strength < 1:
			#strength = 1
		#elif strength > me.vapor / 2:
			#strength = me.vapor / 2
		#flying = state.wind(dest - me.pos, 100)
		flying = state.wind(vec)
		print('flying =', flying)
	else:
		dest_cloud = dest_nearest[0]
		if me.overlap(dest_cloud):
			pass
			#flying = False
		else:
			dist = (dest_cloud.pos - me.pos).length()
			if dist > last_dist + 1:
				flying = False
			else:
				last_dist = dist

	t = time.time() - start
	# use 0.11 seconds as base to make sure we don't break the rules
	time.sleep(0.11 - t)
