#!/usr/bin/env python3
import sys, argparse, random
from math import sqrt, ceil

def main():
    parser = argparse.ArgumentParser(description="General generator for a list of integers.")
    parser.add_argument('-n', metavar='N', type=int, required=True, help='number of int_tuples to generate (at least 1)')
    parser.add_argument('-d', metavar='D', type=int, required=True, help='number representing max distance for edge')
    parser.add_argument('-o', metavar='O', type=str, default="ran", help='options (dash-separated)')
    parser.add_argument('-r', metavar='R', type=int, default=0, help ='how many randomly placed tuples')
    parser.add_argument('-s', metavar='S', type=int, default=None, help='seed')
    args = parser.parse_args()
    random.seed(args.s)

    int_tuples = int_tuple_list_generator(args.n, args.d, args.r, args.o)
    # prints first line consisting of n and d
    
    print(str(len(int_tuples)) + " " + str(args.d))
    print("\n".join(str(x) + " " + str(y) for x, y in int_tuples))


def int_tuple_list_generator(n, d, randoms, options="ran"):
    # Supported options:
    # - ran (set each island to a random one withing (sqrt(n), sqrt(n))
    # - snake (make each island within distance of the last in a line)
    # - disc (make each island too far away from the last island)
    # - rev (reverse the list)

    ## Verify that function is called with sensible parameters
    if (type(n) != int or n <= 0):
        print(f"Invalid value for n: {n}", file=sys.stderr)
        sys.exit(1)
    if (type(d) != int or d <= 0):
        print(f"Invalid value for d: {n}", file=sys.stderr)
        sys.exit(1)
    if (type(options) != str):
        print("Options is not a string", file=sys.stderr)
        sys.exit(1)

    return int_tuple_list_generator_protected(n, d, randoms, options)

def int_tuple_list_generator_protected(n, d, randoms, options):
    int_tuples = [(0, 0)] * n
    radius = d

    for option in options.split('-'):

        # if all points should be disconnected
        if option == "disconnect":
            radius = d + 1

        elif option == "clique":
            count = 0
            int_tuples = []
            for r in range(int(ceil(n**0.5))):
                for c in range(int(ceil(n**0.5))):
                    if count < n:
                        int_tuples.append((r, c))
                        count += 1
        
        # ran: Set each island to a random coordinate with positive values
        elif option == "ran":
            i = 0
            for y in range(int(sqrt(len(int_tuples)))):
                for x in range(int(sqrt(len(int_tuples)))):
                    if i == 0:
                        int_tuples[i] = (x + random.randrange(0, n), y + random.randrange(0, n))
                        i += 1
                    else:
                        int_tuples[i] = (int_tuples[i-1][0] + random.randrange(x, n), int_tuples[i-1][1] + random.randrange(y, n))
                        i += 1

        # grid: creates a sqrt(n) x sqrt(n) grid of points
        elif option == "grid":
            i = 0
            for y in range(int(sqrt(len(int_tuples)))):
                for x in range(int(sqrt(len(int_tuples)))):
                    int_tuples[i] = (x * radius, y * radius)
                    i += 1

        # grid: all points are made in a line
        elif option == "snake":
            for i in range(len(int_tuples)):
                int_tuples[i] = (0, (i * radius))

        # rev: reverse the list
        elif option == "rev":
            int_tuples = list(reversed(int_tuples))
    
    # if specific amount islands should be randomly placed
    if randoms > 0:
        del int_tuples[-randoms:]
        for _ in range(randoms):
            int_tuples.append((int_tuples[-1][0] + random.randrange(1, n), int_tuples[-1][1] + random.randrange(1, n)))
    
    return set(int_tuples)

if __name__ == "__main__":
    main()
