# Copyright (c) 2017-2020 Mateusz Pawlik
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

import random
import string
import argparse
import os

# IMPORTANT: Do not modify the seed for reproducibility.
random.seed(1)

# Process command line parameters.
parser = argparse.ArgumentParser(
    description='Advanced Databases 2019/2020 - Test case generator for validator exercise.')
parser.add_argument(
    type=int,
    dest='number_tests',
    help='Number of test cases to generate.')
parser.add_argument(
    type=int,
    dest='max_t',
    help='Maximum number of transactions in each test case.')
parser.add_argument(
    dest='test_cases_dir',
    help='The test cases are stored in `test_cases_dir` directory.')
args = parser.parse_args()

# Number of tests.
number_tests = args.number_tests

# Number of transactions.
min_t = 2
max_t = args.max_t

# Operation types and their weights. Validation should be less frequently
# chosen than reading or writing.
operations = ['r', 'w', 'v']
op_weights = [0.2, 0.2, 0.1]

# Create `test_cases_dir` directory if needed.
if not os.path.exists(args.test_cases_dir):
    os.makedirs(args.test_cases_dir)

# Generate all test cases.
# Each test case has a random number of transactions, but not more than `max_t`.
for i in range(1, number_tests + 1):
    test_case_file_name = os.path.join(args.test_cases_dir, 'input_%d.txt' % (i, ))
    test_case_file = open(test_case_file_name, 'w+')
    print('--- TEST %d ---' % (i, ))
    
    # Transactions.
    transactions = list(range(1, random.randint(min_t, max_t) + 1))
    # Store transactions that have started. If a transaction has not started,
    # (doesn't have at least one read or write) it can't validate.
    started = set([])
    # Data items.
    letters = string.ascii_lowercase
    data_items = letters

    while transactions:
        # Choose transaction, operation, and data item randomly.
        t = random.choice(transactions)
        # o = random.choice(operations)
        o = random.choices(operations, op_weights, k=1)[0]
        d = random.choice(data_items)

        # If a transaction is chosen to validate, no other operation can be
        # generated for this transaction. Simply remove it from all
        # transactions.
        if o == 'v':
            if t in started:
                transactions.remove(t)
                line = '%s %d' % (o, t)
                print(line)
                print(line, file=test_case_file)
            else:
                continue
        else:
            if t not in started:
                started.add(t)
            line = '%s %d %s' % (o, t, d)
            print(line)
            print(line, file=test_case_file)

    test_case_file.close()
