from typing import List

import Transaction
from DBConnection import postgresConnection
from Transaction import transaction
import random
import numpy as np
from matplotlib import pyplot as plt

def correctVals(vals: List[int]) -> List[int]:
    y = [[] for _ in range(len(vals))]  # truth labels to be estimated
    for i in range(len(vals)):
        if i == 0:
            if vals[i][1] == 0:
                y[i] = 1000 + vals[i][0] * (-1)
            else:
                y[i] = 1000 + vals[i][0]
        else:
            if vals[i][1] == 0:
                y[i] = y[i - 1] - vals[i][0]
            else:
                y[i] = y[i - 1] + vals[i][0]
    y.insert(0, 1000)  # initial bank value
    return y


def valueGenerator() -> List[List[int]]:
    randomlen = random.randrange(5, 8, 1)
    y = [[] for _ in range(randomlen)]
    for i in range(len(y)):
        r = random.randint(0, 1)
        randomval = random.randrange(5, 701, 5)
        y[i] = [randomval, r]
    return y

def scheduleGeneratorBank1(values: List):
    actionlist = [db.sub_val_bank1, db.add_val_bank1]
    for i in range(len(values)):
        # r = random.randint(0, 1)
        Transaction.schedule.append(transaction(i))
        if i == 0:
            Transaction.schedule[i].check = True
        Transaction.schedule[i].setAction(actionlist[values[i][1]], values[i], Transaction.schedule[i].pos)


def scheduleGeneratorBank2(values: List) -> List[List[transaction]]:
    actionlist = [db.sub_val_bank2, db.add_val_bank2]
    schedule = [[] for _ in range(len(values))]
    for i in range(len(values)):
        # r = random.randint(0, 1)
        schedule[i] = transaction(i)
        schedule[i].setAction(actionlist[values[i][1]], values[i])
    return schedule

def sortLabels(labels: np.ndarray, keys: np.ndarray):
    k = keys.copy()
    n = len(labels)
    temp = [0] * n

    for i in range(0, n):
        temp[k[i]] = labels[i]

    for i in range(0, n):
        labels[i] = temp[i]
        k[i] = i

def runSchedule_withLocking(schedule: List[transaction]):
    for t in schedule:
        t.start()
    for t in schedule:
        t.join()

def runSchedule_withoutLocking(schedule: List[transaction]):
    for t in schedule:
        t.start()
    for t in schedule:
        t.join()

def reset():
    values = []
    Transaction.schedule = []
    schedule_bank2 = []
    db.reset_table()

if __name__ == '__main__':

    db = postgresConnection()
    values = []
    schedule_bank2 = []
    lock_results = []
    nolock_results = []

    for i in range(10):
        reset()
        values = valueGenerator()
        scheduleGeneratorBank1(values)
        schedule_bank2 = scheduleGeneratorBank2(values)
        runSchedule_withLocking(Transaction.schedule)
        runSchedule_withoutLocking(schedule_bank2)
        #truth_labels = np.asarray(correctVals(values))
        lock_results.append(db.lockingVals[-1])
        nolock_results.append(db.noLockingVals[-1])

    fig = plt.figure(1)
    xvals = list(range(len(lock_results)))
    lockplot = plt.plot(xvals, lock_results, '-o', color='blue', label='State with locking')
    lockplot = plt.plot(xvals, nolock_results, '-o', color='red', label='State without locking')

    plt.xlabel('Step')
    plt.ylabel('Bank value Final state')
    plt.title('Final state differences')
    plt.legend(loc='upper left')
    plt.show()


