import pyfmi.testcase
import unittest
import itertools
import random
import math

# Our reference solution
def enumerate_rationals():
	def gcd(a, b):
		if b == 0: return a
		return gcd(b, a  % b)

	even = lambda x: x % 2 == 0

	def enumerator():
		row, col = 1, 1
		while True:
			yield row, col
			if even(row +  col): row, col = row + 1, col - 1
			else: row, col = row - 1, col + 1
			if row < 1: row = 1
			if col < 1: col = 1

	return itertools.ifilter(lambda ab: gcd(*ab) == 1, enumerator())

def primed(iterator):
	# This should be implemented with itertools.ifilter()
	def is_prime(num):
		if num <= 1: return False
		if num == 2: return True
		checkTo = int(math.sqrt(num)) + 1
		for divisor in xrange(2, checkTo):
			if num % divisor == 0:
				return False
		return True
	def prime_asc_filter(xy):
		x, y = xy
		return x < y and is_prime(x) and is_prime(y)
	return itertools.ifilter(prime_asc_filter, iterator)

points = 5

class ProblemTests(pyfmi.testcase.SpeakingTestCase):

	larger = 5
	huge = 11 # Used to be sth like 1500, but the implementations sucked, so...

	def compare(self, iterator, expected):
		self.assertEqual(
			tuple(itertools.islice(iterator, len(expected))), 
			expected
		)

	def sample(self, iterator, size):
		return tuple(itertools.islice(iterator, size))

	def test_enumerate_simple(self):
		enumerate_expected = (1, 1), (2, 1), (1, 2), (1, 3), (3, 1), (4, 1), (3, 2), (2, 3), (1, 4), (1, 5), (5, 1)
		self.compare(self.user.enumerate_rationals(), enumerate_expected)
		enumerate_larger_sample = self.sample(enumerate_rationals(), self.larger)
		self.compare(self.user.enumerate_rationals(), enumerate_larger_sample)

	def test_both_simple(self):
		primed_expected = (2, 3), (2, 5), (3, 5)
		self.compare(self.user.primed(self.user.enumerate_rationals()), primed_expected)
		primed_larger_sample = self.sample(primed(enumerate_rationals()), self.larger)
		self.compare(self.user.primed(self.user.enumerate_rationals()), primed_larger_sample)

	def test_enumerate_huge(self):
		enumerate_huge_sample = self.sample(enumerate_rationals(), self.huge)
		self.compare(self.user.enumerate_rationals(), enumerate_huge_sample)

	def test_both_huge(self):
		primed_huge_sample = self.sample(primed(enumerate_rationals()), self.huge)
		self.compare(self.user.primed(self.user.enumerate_rationals()), primed_huge_sample)

	def test_primed(self):
		data = (1, 1), (1, 1), (1, 1), (2, 1), (2, 1), (0, 0), (-1, -10), (1, 3), (0, 3), (11, 37), (2, 3), (2, 3)
		expected = (11, 37), (2, 3), (2, 3)
		self.compare(self.user.primed(iter(data)), expected)
		def tuple_generator():
			rand_max = 65535
			while True: yield int(random.random() * rand_max), int(random.random() * rand_max)
		data = self.sample(tuple_generator(), self.larger)
		self.compare(
			self.user.primed(iter(data)), 
			tuple(primed(iter(data)))
		)
		# Test empties
		data, expected = tuple(), tuple()
		self.compare(self.user.primed(iter(data)), expected)

if __name__ == '__main__':
	ProblemTests.user_filename = 'p6.py'
	unittest.main()
