from __future__ import print_function
from basic_service import *
from keras.optimizers import RMSprop, Adagrad, Adam


def select_roi(image_orig, image_bin):
    # plt.imshow(image_bin)
    '''
    Funkcija kao u vežbi 2, iscrtava pravougaonike na originalnoj slici, pronalazi sortiran niz regiona sa slike,
    i dodatno treba da sačuva rastojanja između susednih regiona.
    '''
    img, contours, hierarchy = cv2.findContours(image_bin.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # Način određivanja kontura je promenjen na spoljašnje konture: cv2.RETR_EXTERNAL
    regions_array = []
    regije_kvacica = []

    for contour in contours:
        x, y, w, h = cv2.boundingRect(contour)
        area = cv2.contourArea(contour)
        # print(area)
        if area > 100 and 100 > h > 15 and w > 20:
            region = image_bin[y:y + h + 1, x:x + w + 1]
            regije_kvacica.append([resize_region(region), (x, y, w, h)])
            # cv2.rectangle(image_orig,(x,y),(x+w,y+h),(0,255,0),2)
        else:
            if area > 200:  # OVDE NEKU PAMETNIJU LOGIKU NAPRAVITI
                # print("koristan region velicine: " + str(area))
                region = image_bin[y:y + h + 1, x:x + w + 1]
                regions_array.append([resize_region(region), (x, y, w, h)])
                # cv2.rectangle(image_orig,(x,y),(x+w,y+h),(0,255,0),2)
    # print("ukupno kontura: " + str(len(contours)))
    # plt.imshow(image_bin.copy(),'gray')
    # image_crtanje = image_orig.copy()
    # cv2.drawContours(image_crtanje, contours, -1, (255, 0, 0), 2)
    # plt.imshow(image_crtanje)

    # TODO: Smisliti kako spojiti kvacice i slova
    regions_array = sorted(regions_array, key=lambda item: item[1][0])

    sorted_regions = [region[0] for region in regions_array]
    plt.imshow(sorted_regions[8])

    sorted_rectangles = [region[1] for region in regions_array]
    region_distances = []
    # Izdvojiti sortirane parametre opisujućih pravougaonika
    # Izračunati rastojanja između svih susednih regiona po x osi i dodati ih u region_distances niz
    for index in range(0, len(sorted_rectangles) - 1):
        current = sorted_rectangles[index]
        next_rect = sorted_rectangles[index + 1]
        distance = next_rect[0] - (current[0] + current[2])  # X_next - (X_current + W_current)
        region_distances.append(distance)

    return image_orig, sorted_regions, region_distances


def create_ann():
    '''
    Implementirati veštačku neuronsku mrežu sa 28x28 ulaznih neurona i jednim skrivenim slojem od 128 neurona.
    Odrediti broj izlaznih neurona. Aktivaciona funkcija je sigmoid.
    '''
    ann = Sequential()
    # Postaviti slojeve neurona mreže 'ann'
    # ann.add(Dense(512, input_dim=784, activation='sigmoid'))
    # ann.add(Dense(128, input_dim=512, activation='sigmoid'))

    ann.add(Dense(128, input_dim=784, activation='sigmoid'))
    # 2/3 from 784 is 517 + output is 577 neuron
    # ann.add(Dense(128, activation='sigmoid'))
    # ann.add(Dense(30, input_dim=128, activation='sigmoid'))
    ann.add(Dense(60, activation='sigmoid'))
    return ann


def train_ann(ann, X_train, y_train):
    X_train = np.array(X_train, np.float32)
    y_train = np.array(y_train, np.float32)

    # definisanje parametra algoritma za obucavanje
    opt = SGD(lr=0.5, momentum=0.9)
    # opt = Adam()
    ann.compile(loss='mean_squared_error', optimizer=opt)
    # PROBATI DRUGU LOSS FJU
    # obucavanje neuronske mreze
    ann.fit(X_train, y_train, epochs=500, batch_size=1, verbose=1, shuffle=True)

    return ann


def serialize_ann(ann):
    # serijalizuj arhitekturu neuronske mreze u JSON fajl
    model_json = ann.to_json()
    with open("serialized_model/neuronska.json", "w") as json_file:
        json_file.write(model_json)
    # serijalizuj tezine u HDF5 fajl
    ann.save_weights("serialized_model/neuronska.h5")


def load_trained_ann():
    try:
        # Ucitaj JSON i kreiraj arhitekturu neuronske mreze na osnovu njega
        json_file = open('serialized_model/neuronska.json', 'r')
        loaded_model_json = json_file.read()
        json_file.close()
        ann = model_from_json(loaded_model_json)
        # ucitaj tezine u prethodno kreirani model
        ann.load_weights("serialized_model/neuronska.h5")
        print("Istrenirani model uspesno ucitan.")
        return ann
    except Exception as e:
        # ako ucitavanje nije uspelo, verovatno model prethodno nije serijalizovan pa nema odakle da bude ucitan
        return None
