import string
import os
import random
import sys

MAX_N = 10**5

CASE = 10
DEST = os.path.join(os.getcwd(), '../data/secret')

def next_file(short_desc=None, long_desc=None):
    global CASE
    basename = os.path.join(DEST, '%02d' % CASE)
    CASE += 1
    if short_desc is not None:
        basename += '-' + short_desc
    if long_desc is not None:
        with open(basename+'.desc', 'w') as desc_out:
            desc_out.write(long_desc)
    return open(basename+'.in', 'w')

def save_case(first, remain, short_desc=None, long_desc=None, shuffle_adj_list=True):
    assert(len(set(list(remain) + [first])) == len(remain) + 1)
    sys.stderr.write('save case %d\n' % (len(remain)))
    f = next_file(short_desc, long_desc)
    f.write('%s\n%d\n%s\n' % (first, len(remain), '\n'.join(remain)))
    f.close()


def rand_str(MinL, MaxL, alphabet=string.lowercase):
    L = random.randint(MinL, MaxL)
    return ''.join(random.choice(alphabet) for _ in range(L))

def rand_edge(start, end, MinL, MaxL, alphabet=string.lowercase):
    return start + rand_str(MinL-2, MaxL-2, alphabet=alphabet) + end


def random_impossible(N, MinL, MaxL, alph_size=26):
    alphabet = random.sample(string.lowercase, alph_size)
    first = rand_str(MinL, MaxL, alphabet=alphabet)
    names = set([first])
    while len(names) < N+1:
        w = rand_str(MinL, MaxL, alphabet=alphabet)
        if w[0] != first[-1]: names.add(w)
    names.remove(first)
    names = list(names)
    random.shuffle(names)
    save_case(first, names, short_desc='random_impossible')

def random_possible(N, MinL, MaxL, alph_size=26):
    alphabet = random.sample(string.lowercase, alph_size)
    first = rand_str(MinL, MaxL, alphabet=alphabet)
    names = set([first])
    while len(names) < N+1:
        w = rand_str(MinL, MaxL, alphabet=alphabet)
        if (w[0] != first[-1]) ^ (len(names) == 0): names.add(w)
    names.remove(first)
    names = list(names)
    random.shuffle(names)
    save_case(first, names, short_desc='random_possible')

def random_win(N, MinL, MaxL, alph_size=26, solutions=1):
    alphabet = random.sample(string.lowercase, alph_size)
    first = rand_str(MinL, MaxL, alphabet=alphabet)
    second = first
    while second == first:
        second = rand_edge(first[-1], random.choice(alphabet), MinL, MaxL, alphabet=alphabet)
        if solutions > 1 and second[0] == second[-1]: second = first
    names = set([first, second])
    while len(names) < 1+solutions:
        names.add(rand_edge(second[0], second[-1], MinL, MaxL, alphabet=alphabet))
    while len(names) < 1+N:
        w = rand_str(MinL, MaxL, alphabet=alphabet)
        if w[0] != second[-1] and (w[0] != second[0] or w[-1] != second[-1]):
            names.add(w)
    names.remove(first)
    names = list(names)
    random.shuffle(names)
    save_case(first, names, short_desc='random_win')


def main():
    random.seed(13)

    save_case('x', 'abcdefghijklmnopqrstuvwyz', short_desc='single_letters')
    save_case('x', ['xx', 'xxx'])
    save_case('apa', ['a', 'aa', 'aaa'])
    save_case('apa', ['c', 'b', 'a'])
    
    N_scale = 10
    for _ in range(4):
        random_impossible(random.randint(N_scale, 10*N_scale),
                          1, 15, random.randint(2, 26))
        random_possible(random.randint(N_scale, 10*N_scale),
                        1, 15, random.randint(2, 26))
        random_win(random.randint(N_scale, 10*N_scale),
                   1, 15, random.randint(2, 26), random.randint(1, 2))
        N_scale *= 10

    random_impossible(MAX_N, 20, 20, alph_size=2)
    random_impossible(MAX_N, 20, 20)
    random_possible(MAX_N, 20, 20, alph_size=2)
    random_possible(MAX_N, 20, 20)
    random_win(MAX_N, 20, 20, alph_size=2)
    random_win(MAX_N, 20, 20, solutions=MAX_N)
    random_win(MAX_N, 20, 20)

if __name__=='__main__':
    main()
