#!/bin/env python3

import argparse
import math
import matplotlib.pyplot as plt

units = [1, -1, 1j, -1j]

def is_prime(x):
	if x <= 1: return False
	if x == 2: return True
	elif x % 2 == 0: return False
	i = 3
	while i*i <= x:
		if x % i == 0:
			return False
		i += 2
	return True

def norm(x):
	return x.real*x.real + x.imag*x.imag

def is_gaussian_prime(x):
	if x.real != 0 and x.imag != 0:
		return is_prime(norm(x))
	elif x.real != 0:
		return is_prime(abs(x.real)) and (abs(x.real)-3) % 4 == 0
	elif x.imag != 0:
		return is_prime(abs(x.imag)) and (abs(x.imag)-3) % 4 == 0
	else:
		return False

def sum_of_squares(x):
	r = []
	i = math.ceil(math.sqrt(x))
	while i > 0:
		j = 0
		while j <= i:
			if j*j + i*i == x:
				r.append([i, j])
			j += 1
		i -= 1
	return r

def divisors(x):
	r = set()
	if x % 2 == 0:
		r.add(2)
		r.add(x//2)
	i = 3
	while i*i < x:
		if x % i == 0:
			r.add(i)
			r.add(x//i)
		i += 2
	if i*i == x:
		r.add(i)
	return r

def nfactors(x):
	return sorted([d for d in divisors(x) if is_prime(d)])

def gifactors(x):
	r = []
	for d in nfactors(norm(x)):
		if is_gaussian_prime(d):
			r.append(d)
		elif is_prime(d):
			t = sum_of_squares(d)
			r += [(s[0]+s[1]*1j) for s in t]
			r += [(s[0]-s[1]*1j) for s in t if s[1] != 0]
	return r

def gidivisible(a, b):
	x = a*b.conjugate()
	nb = norm(b)
	return (x.real % nb == 0) and (x.imag % nb == 0)

def gidivisors(n):
	r = set()
	nn = norm(n)
	for x in range(0, n+1):
		for y in range(0, n+1):
			g = (x+y*1j)
			if g != 0 and gidivisible(n, g):
				r.update([g*u for u in units])
	return r

def points_from_divisors(d):
	return [(x.real, x.imag) for x in d]

def plot(x):
	data = points_from_divisors(gidivisors(x))
	plt.scatter([d[0] for d in data], [d[1] for d in data])
	plt.show()

def csv(x, text=True):
	r = []
	for p in points_from_divisors(gidivisors(x)):
		r.append("{},{},{}".format(int(p[0]), int(p[1]), x))
	if text:
		return "\n".join(r)
	else:
		return r

if __name__ == "__main__":
	parser = argparse.ArgumentParser()
	parser.add_argument("value", type=int)
	parser.add_argument("--csv", action="store_true")
	args = parser.parse_args()
	if args.csv:
		print(csv(args.value))
	else:
		plot(args.value)

