from __future__ import print_function
import argparse
# import skimage
# import skimage.io
# import skimage.transform
from PIL import Image
from math import log10
import math
import matplotlib.pyplot as plt
import sys
import csv
import cv2
import shutil
import os
import re
from struct import unpack
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.backends.cudnn as cudnn
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data import DataLoader

# from dataloader.data import get_test_set
import numpy as np

parser = argparse.ArgumentParser(description='PyTorch GANet Example')
parser.add_argument('--crop_height', type=int, required=True, help="crop height")
parser.add_argument('--crop_width', type=int, required=True, help="crop width")
parser.add_argument('--max_disp', type=int, default=192, help="max disp")
parser.add_argument('--resume', type=str, default='', help="resume from saved model")
parser.add_argument('--cuda', type=bool, default=True, help='use cuda?')
parser.add_argument('--kitti', type=int, default=0, help='kitti dataset? Default=False')
parser.add_argument('--kitti2015', type=int, default=0, help='kitti 2015? Default=False')
parser.add_argument('--data_path', type=str, required=True, help="data root")
parser.add_argument('--test_list', type=str, required=True, help="training list")
parser.add_argument('--save_path', type=str, default='./result/', help="location to save result")
parser.add_argument('--threshold', type=float, default=3.0, help="threshold of error rates")
parser.add_argument('--multi_gpu', type=int, default=0, help="multi_gpu choice")
parser.add_argument('--middlebury', type=int, default=0, help="middlebury dataset?")
parser.add_argument('--eth3d', type=int, default=0, help="ETH3D dataset?")
parser.add_argument('--benchmark', type=int, default=0, help="Kitti benchmark submission?")
parser.add_argument('--model', type=str, default='GANet_ms', help="model to use")

opt = parser.parse_args()

print(opt)
if opt.model == 'GANet11':
    from models.GANet11 import GANet
elif opt.model == 'GANet_deep':
    from models.GANet_deep import GANet
elif opt.model == 'GANet_ms':
    from models.GANet_ms import GANet
else:
    raise Exception("No suitable model found ...")

cuda = opt.cuda

if cuda and not torch.cuda.is_available():
    raise Exception("No GPU found, please run without --cuda")

# print('===> Loading datasets')
# test_set = get_test_set(opt.data_path, opt.test_list, [opt.crop_height, opt.crop_width], false, opt.kitti, opt.kitti2015)
# testing_data_loader = DataLoader(dataset=test_set, num_workers=opt.threads, batch_size=opt.testBatchSize, shuffle=False)

print('===> Building model')
model = GANet(opt.max_disp)

if cuda:
    model = torch.nn.DataParallel(model).cuda()

if opt.resume:
    if os.path.isfile(opt.resume):
        print("=> loading checkpoint '{}'".format(opt.resume))
        checkpoint = torch.load(opt.resume)
        model.load_state_dict(checkpoint['state_dict'], strict=False)

    else:
        print("=> no checkpoint found at '{}'".format(opt.resume))

def readPFM(file):
    with open(file, "rb") as f:
        # Line 1: PF=>RGB (3 channels), Pf=>Greyscale (1 channel)
        type = f.readline().decode('latin-1')
        if "PF" in type:
            channels = 3
        elif "Pf" in type:
            channels = 1
        else:
            print(file, ': ** NOT a valid .pfm file ***')
            sys.exit(1)
        # Line 2: width height
        line = f.readline().decode('latin-1')
        width, height = re.findall('\d+', line)
        width = int(width)
        height = int(height)

        # Line 3: +ve number means big endian, negative means little endian
        line = f.readline().decode('latin-1')
        BigEndian = True
        if "-" in line:
            BigEndian = False
        # Slurp all binary data
        samples = width * height * channels
        buffer = f.read(samples * 4)
        # Unpack floats with appropriate endianness
        if BigEndian:
            fmt = ">"
        else:
            fmt = "<"
        fmt = fmt + str(samples) + "f"
        img = unpack(fmt, buffer)
        img = np.reshape(img, (height, width))
        img = np.flipud(img)
    return img, height, width

def readPNG(file):
    png_disp = Image.open(file)
    png_disp.load()
    png_disp = np.asarray(png_disp)

    # summarize some details about the image
    width = png_disp.shape[0]
    height = png_disp.shape[-1]

    return png_disp, height, width

def test_transform(temp_data, crop_height, crop_width):
    _, h, w = np.shape(temp_data)
    print(np.shape(temp_data))
    if h <= crop_height and w <= crop_width:
        temp = temp_data
        temp_data = np.zeros([6, crop_height, crop_width], 'float32')
        temp_data[:, crop_height - h: crop_height, crop_width - w: crop_width] = temp
    else:
        print("in smaller crop width")
        start_x = int((w - crop_width) / 2)
        start_y = int((h - crop_height) / 2)
        temp_data = temp_data[:, start_y: start_y + crop_height, start_x: start_x + crop_width]
    left = np.ones([1, 3, crop_height, crop_width], 'float32')
    left[0, :, :, :] = temp_data[0: 3, :, :]
    right = np.ones([1, 3, crop_height, crop_width], 'float32')
    right[0, :, :, :] = temp_data[3: 6, :, :]
    return torch.from_numpy(left).float(), torch.from_numpy(right).float(), h, w

def disp_transform(temp_data, crop_height, crop_width):
    h, w = np.shape(temp_data)

    if h <= crop_height and w <= crop_width:
        temp = temp_data
        temp_data = np.zeros([crop_height, crop_width], 'float32')
        temp_data[crop_height - h: crop_height, crop_width - w: crop_width] = temp
    else:
        start_x = int((w - crop_width) / 2)
        start_y = int((h - crop_height) / 2)
        temp_data = temp_data[start_y: start_y + crop_height, start_x: start_x + crop_width]
    left = np.ones([crop_height, crop_width], 'float32')
    left[:, :] = temp_data[:, :]
    return left

def load_data(leftname, rightname, c_height, c_width):
    left = Image.open(leftname)
    right = Image.open(rightname)
    size = np.shape(left)
    height = size[0]
    width = size[1]
    s_fac = None
    dim = None

    if height > c_height or width > c_width:
        s_fac = (c_height / height, c_width / width)
        dim = (width, height)
        print('===> using resizing')
        new_size = (c_width, c_height)
        left = left.resize(new_size, resample=Image.BICUBIC)
        right = right.resize(new_size, resample=Image.BICUBIC)
        height = c_height
        width = c_width

    temp_data = np.zeros([6, height, width], 'float32')
    left = np.asarray(left)
    right = np.asarray(right)
    r = left[:, :, 0]
    g = left[:, :, 1]
    b = left[:, :, 2]
    temp_data[0, :, :] = (r - np.mean(r[:])) / np.std(r[:])
    temp_data[1, :, :] = (g - np.mean(g[:])) / np.std(g[:])
    temp_data[2, :, :] = (b - np.mean(b[:])) / np.std(b[:])
    r = right[:, :, 0]
    g = right[:, :, 1]
    b = right[:, :, 2]
    # r,g,b,_ = right.split()
    temp_data[3, :, :] = (r - np.mean(r[:])) / np.std(r[:])
    temp_data[4, :, :] = (g - np.mean(g[:])) / np.std(g[:])
    temp_data[5, :, :] = (b - np.mean(b[:])) / np.std(b[:])
    return s_fac, dim, temp_data

def test(leftname, rightname, savename, disp_max):
    s_fac , dim, img_data = load_data(leftname, rightname, opt.crop_height, opt.crop_width)
    input1, input2, height, width = test_transform(img_data, opt.crop_height, opt.crop_width)
    input1 = Variable(input1, requires_grad=False)
    input2 = Variable(input2, requires_grad=False)

    model.eval()
    if cuda:
        input1 = input1.cuda()
        input2 = input2.cuda()
    with torch.no_grad():
        prediction = model(input1, input2)

    temp = prediction.cpu()
    temp = temp.detach().numpy()
    if height <= opt.crop_height and width <= opt.crop_width:
        temp = temp[0, opt.crop_height - height: opt.crop_height, opt.crop_width - width: opt.crop_width]
        # temp = temp[0, :, :]
    else:
        temp = temp[0, :, :]

    if s_fac is not None:
        temp = Image.fromarray(temp).resize(dim, resample=Image.LANCZOS)
        print("===> Scaling factor: ", s_fac[1])
        temp = np.asarray(temp) * 1/(s_fac[1])

    if opt.benchmark == 1:
        skimage.io.imsave(savename, (temp * 256).astype('uint16'))
    else:
        dmap_norm = (temp / disp_max) * 256
        # dmap_norm = cv2.normalize(temp.astype('uint8'), None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
        im_color = cv2.applyColorMap(dmap_norm.astype('uint8'), cv2.COLORMAP_JET)
        cv2.imwrite(savename, im_color)

    return temp

def apply_custom_colormap(image_gray, cmap=plt.get_cmap('jet')):
    assert image_gray.dtype == np.uint8, 'must be np.uint8 image'
    if image_gray.ndim == 3: image_gray = image_gray.squeeze(-1)

    # Initialize the matplotlib color map
    sm = plt.cm.ScalarMappable(cmap=cmap)

    # Obtain linear color range
    color_range = sm.to_rgba(np.linspace(0, 1, 256))[:, 0:3]  # color range RGBA => RGB
    color_range = (color_range * 255.0).astype(np.uint8)  # [0,1] => [0,255]
    color_range = np.squeeze(np.dstack([color_range[:, 2], color_range[:, 1], color_range[:, 0]]), 0)  # RGB => BGR

    # Apply colormap for each channel individually
    image_gray = cv2.normalize(image_gray, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
    channels = [cv2.LUT(image_gray, color_range[:, i]) for i in range(3)]
    return np.dstack(channels)

if __name__ == "__main__":
    file_path = opt.data_path
    file_list = opt.test_list
    f = open(file_list, 'r')
    filelist = f.readlines()
    avg_error = 0
    avg_rate = 0
    skipped = 0
    for index in range(len(filelist)):
        current_file = filelist[index]
        if opt.kitti2015:
            leftname = file_path + 'image_2/' + current_file[0: len(current_file) - 1]
            rightname = file_path + 'image_3/' + current_file[0: len(current_file) - 1]
            if opt.benchmark==1:
                dispname = "/ds-av/public_datasets/kitti2015/raw/training/" + 'disp_occ_0/' + current_file[0: len(current_file) - 1]
            else:
                dispname = file_path + 'disp_occ_0/' + current_file[0: len(current_file) - 1]
            savename = opt.save_path + current_file[0: len(current_file) - 1]
            disp = Image.open(dispname)
            disp = np.asarray(disp) / 256.0
        elif opt.kitti:
            leftname = file_path + 'colored_0/' + current_file[0: len(current_file) - 1]
            rightname = file_path + 'colored_1/' + current_file[0: len(current_file) - 1]
            dispname = file_path + 'disp_occ/' + current_file[0: len(current_file) - 1]
            savename = opt.save_path + current_file[0: len(current_file) - 1]
            disp = Image.open(dispname)
            disp = np.asarray(disp) / 256.0
        elif opt.middlebury:
            leftname = opt.data_path + current_file[0: len(current_file) - 1]
            try:
                rightname = opt.data_path + current_file[0: len(current_file) - 8] + 'im1.png'
                dispname = opt.data_path + current_file[0: len(current_file) - 8] + 'disp0GT.pfm'
                f = open(rightname)
                f.close()
                disp, height, width = readPFM(dispname)
            except:
                rightname = opt.data_path + current_file[0: len(current_file) - 10] + 'view5.png'
                dispname = opt.data_path + current_file[0: len(current_file) - 10] + 'disp1.png'
                disp, height, width = readPNG(dispname)
                # disp = Image.open(dispname)
                # disp = np.asarray(disp)

            savename = opt.save_path + str(index) + '.png'

            # try:
            #     with open(opt.data_path + current_file[0: len(current_file) - 8] + 'calib.txt') as f:
            #         d = {}
            #         for line in f:
            #             (key, val) = line.split('=')
            #             d[key] = val
            #     # print(d['cam0'].split(" ")[0][1:])
            #     disp = float(d['baseline']) * float(d['cam0'].split(" ")[0][1:]) / (disp + float(d['doffs']))
            #     # print(disp)
            # except:
            #     print("\nRunning without calib.txt...")

        elif opt.eth3d:
            leftname = opt.data_path + current_file[0: len(current_file) - 1]
            rightname = opt.data_path + current_file[0: len(current_file) - 8] + 'im1.png'
            dispname = opt.data_path + current_file[0: len(current_file) - 8] + 'disp0GT.pfm'
            savename = opt.save_path + str(index) + '.png'
            # print("Reading ETH3D images...", dispname)
            disp, height, width = readPFM(dispname)
            # print("Calculating Disparity...", dispname)
        else:
            leftname = opt.data_path + 'frames_finalpass/' + current_file[0: len(current_file) - 1]
            rightname = opt.data_path + 'frames_finalpass/' + current_file[
                                                              0: len(current_file) - 14] + 'right/' + current_file[len(
                current_file) - 9:len(current_file) - 1]
            dispname = opt.data_path + 'disparity/' + current_file[0: len(current_file) - 4] + 'pfm'
            savename = opt.save_path + str(index) + '.png'
            disp, height, width = readPFM(dispname)

        disp_max = disp.max()
        prediction = test(leftname, rightname, savename, disp_max)
        if opt.benchmark == 1:
            print("===> Frame {}: ".format(index) + current_file[0:len(
                current_file) - 1] )
            continue
        mask = np.logical_and(disp >= 0.001, disp <= 192)

        error = np.mean(np.abs(prediction[mask] - disp[mask]))
        rate = np.sum(np.abs(prediction[mask] - disp[mask]) > opt.threshold) / np.sum(mask)
        avg_error += error
        avg_rate += rate
        print("===> Frame {}: ".format(index) + current_file[0:len(
            current_file) - 1] + " ==> EPE Error: {:.4f}, Error Rate: {:.4f}".format(error, rate))

        dmap_norm = cv2.normalize(disp.astype('uint8'), None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
        im_color = cv2.applyColorMap(dmap_norm, cv2.COLORMAP_JET)
        cv2.imwrite(savename[0: len(savename) - 3] + 'disp.png', im_color)
        # if disp.shape == prediction.shape:
        #     # mask = np.logical_and(disp >= 0.001, disp <= opt.max_disp)
        #     mask = np.logical_and(disp >= 0.001, disp <= 192)
        #     error = np.mean(np.abs(prediction[mask] - disp[mask]))
        #     # skimage.io.imsave(savename[0: len(savename)- 3] + 'disp.png', (disp * 256).astype('uint16'))
        #     dmap_norm = cv2.normalize(disp.astype('uint8'), None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
        #     im_color = cv2.applyColorMap(dmap_norm, cv2.COLORMAP_JET)
        #     cv2.imwrite(savename[0: len(savename) - 3] + 'disp.png', im_color)

        # else:
        #     if opt.benchmark == 1:
        #         continue
        #     # new_size= (opt.crop_width, opt.crop_height)
        #     # disp = np.asarray(Image.fromarray(disp).resize(new_size), dtype=float)
        #     disp = disp_transform(disp, opt.crop_height, opt.crop_width)
        #     print("Scale Factor: ", opt.crop_width / width)
        #     disp = np.multiply(disp, opt.crop_width / width)
        #     # skimage.io.imsave(savename[0: len(savename)- 3] + 'disp.png', (disp * 256).astype('uint16'))
        #     dmap_norm = cv2.normalize(disp.astype('uint8'), None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
        #     im_color = cv2.applyColorMap(dmap_norm, cv2.COLORMAP_JET)
        #     cv2.imwrite(savename[0: len(savename) - 3] + 'disp.png', im_color)
        #
        #     # print('Disp.shape: ', disp.shape)
        #
        #     # mask = np.logical_and(disp >= 0.001, disp <= opt.max_disp)
        #     mask = np.logical_and(disp >= 0.001, disp <= 192)
        #     error = np.mean(np.abs(prediction[mask] - disp[mask]))
        #
        # print('Disp.shape: ', disp.shape)
        # print('Prediction.shape: ', prediction.shape)
        # rate = np.sum(np.abs(prediction[mask] - disp[mask]) > opt.threshold) / np.sum(mask)
        # if math.isnan(rate):
        #     print('++> Prediction Mask False due to low max_disp value... Skipping frame.')
        #     skipped += 1
        #     continue
        #
        # # print("Rate: ", rate)
        # # exit(0)
        # avg_error += error
        # avg_rate += rate
        # print("===> Frame {}: ".format(index) + current_file[0:len(
        #     current_file) - 1] + " ==> EPE Error: {:.4f}, Error Rate: {:.4f}".format(error, rate))
    avg_error = avg_error / len(filelist)
    avg_rate = avg_rate / len(filelist)
    print("===> Total {} Frames ==> AVG EPE Error: {:.4f}, AVG Error Rate: {:.4f}, Skipped: {:}".format(len(filelist), avg_error, avg_rate, skipped))


import re
import sys
import os
import pkg_resources
from io import TextIOWrapper
from sklearn.cluster import KMeans
from sklearn.ensemble import RandomForestClassifier
import numpy as np
from argparse import Namespace

from .protein_functions import is_phage_func, is_unknown_func, is_not_phage_func, is_mobile_element
from .genbank_accessory_functions import feature_id
from .log_and_message import log_and_message

def find_training_genome(training_flag):
    try:
        f = pkg_resources.resource_stream('PhiSpyModules', 'data/trainingGenome_list.txt')
    except IOError as e:
        log_and_message(f"There was an error opening data/trainingGenome_list.txt: {e}\n", c="RED", stderr=True,
                        loglevel="CRITICAL")
        return ''

    for line in f:
        temp = re.split('\t', line.decode().strip())
        if int(temp[0]) == training_flag:
            f.close()
            return temp[1].strip()
    return ''

def call_randomforest(**kwargs):
    training_file = kwargs['training_set']
    test_data = kwargs['test_data']

    if not pkg_resources.resource_exists('PhiSpyModules', training_file):
        log_and_message(f"FATAL: Can not find data file {training_file}\n", c="RED", stderr=True, loglevel="CRITICAL")
        sys.exit(11)
    strm = pkg_resources.resource_stream('PhiSpyModules', training_file)
    log_and_message(f"Using training set in {training_file}")
    train_data = np.genfromtxt(TextIOWrapper(strm), delimiter="\t", skip_header=1, filling_values=1)

    all_metrics = ['orf_length_med', 'shannon_slope', 'at_skew', 'gc_skew', 'max_direction', 'phmms']
    if kwargs['phmms']:
        kwargs['metrics'].append('phmms')

    if len(kwargs['metrics']) < len(all_metrics):
        used = b=set(kwargs['metrics']) & set(all_metrics)
        log_and_message(f"Using the following metric(s): {used}.", c='GREEN', stderr=True, quiet=kwargs['quiet'])
        skip_metrics = [all_metrics.index(x) for x in set(all_metrics) - used]
        train_data = np.delete(train_data, skip_metrics, 1)
        test_data = np.delete(test_data, skip_metrics, 1)
    else:
        log_and_message(f"Using all metrics: {', '.join(all_metrics)}.", c='GREEN', stderr=True, quiet=kwargs['quiet'])

    """
    Przemek's comment
    by default 10 until version 0.22 where default is 100
    number of estimators also implies the precision of probabilities, generally 1/n_estimators
    in R's randomForest it's 500 and the usage note regarding number of trees to grow says:
    "This should not be set to too small a number, to ensure that every input row gets predicted at least a few times."
    """
    log_and_message(f"Running the random forest classifier with {kwargs['randomforest_trees']} trees and {kwargs['threads']} threads", c='GREEN', stderr=True, quiet=kwargs['quiet'])
    if train_data.shape[1] > 1:
        clf = RandomForestClassifier(n_estimators=kwargs['randomforest_trees'], n_jobs=kwargs['threads'])
        clf.fit(train_data[:, :-1], train_data[:, -1].astype('int'))
        return clf.predict_proba(test_data)[:,1]
    else:
        log_and_message("None of the metrics were requested and so we did not run the random forest. Results may be variable.", c='PINK', stderr=True, quiet=kwargs['quiet'])
        return np.zeros(len(kwargs['test_data']))

def my_sort(orf_list):
    n = len(orf_list)
    i = 1
    while i <= n:
        j = i + 1
        while j < n:
            flag = 0
            # direction for both
            if orf_list[i]['start'] < orf_list[i]['stop']:
                dir_i = 1
            else:
                dir_i = -1
            if orf_list[j]['start'] < orf_list[j]['stop']:
                dir_j = 1
            else:
                dir_j = -1

            # check whether swap need or not
            if dir_i == dir_j:
                if orf_list[i]['start'] > orf_list[j]['start']:
                    flag = 1
            else:
                if dir_i == 1:
                    if orf_list[i]['start'] > orf_list[j]['stop']:
                        flag = 1
                else:
                    if orf_list[i]['stop'] > orf_list[j]['start']:
                        flag = 1
            # swap
            if flag == 1:
                temp = orf_list[i]
                orf_list[i] = orf_list[j]
                orf_list[j] = temp
            j = j+1
        i = i+1
    return orf_list

def find_mean(all_len):
    s = 0.0
    for i in all_len:
        s = s + i
    return float(s)/len(all_len)

def calc_pp(func):
    func = func.replace('-', ' ')
    func = func.replace(',', ' ')
    func = func.replace('/', ' ')
    func = func.lower()
    x = 0
    if is_phage_func(func):
        x = 1
    elif is_mobile_element(func):
        x = 0.75
    elif is_unknown_func(func):
        x = 0.5

    if is_not_phage_func(func):
        x = 0

    # a few special cases
    if 'recombinase' in func or 'integrase' in func:
        x = 1.5

    return x

"""
Artemis colour codes
These come from the Setting Colours section of
https://sanger-pathogens.github.io/Artemis/Artemis/artemis-manual.pdf
0 white (RGB values: 255 255 255)
1 dark grey (RGB values: 100 100 100)
2 red (RGB values: 255 0 0)
3 green (RGB values: 0 255 0)
4 blue (RGB values: 0 0 255)
5 cyan (RGB values: 0 255 255)
6 magenta (RGB values: 255 0 255)
7 yellow (RGB values: 255 255 0)
8 pale green (RGB values: 152 251 152)
9 light sky blue (RGB values: 135 206 250)
10 orange (RGB values: 255 165 0)
11 brown (RGB values: 200 150 100)
12 pale pink (RGB values: 255 200 200)
13 light grey (RGB values: 170 170 170)
14 black (RGB values: 0 0 0)
15 mid red: (RGB values: 255 63 63)
16 light red (RGB values: 255 127 127)
17 pink (RGB values: 255 191 191)
"""

def make_initial_tbl(**kwargs):
    self = Namespace(**kwargs)
    data = []
    x = []
    for entry in self.record:
        for feature in entry.get_features('CDS'):
            if self.include_annotations:
                pp_score = calc_pp(feature.function)
            else:
                pp_score = 0
            if self.color:
                if pp_score > 1:
                    feature.qualifiers['colour'] = 2 # red
                elif pp_score == 0.75:
                    feature.qualifiers['colour'] = 6 # pink
                elif pp_score == 1:
                    feature.qualifiers['colour'] = 4 # blue
                elif is_unknown_func(feature.function):
                    feature.qualifiers['colour'] = 13  # light grey
                elif pp_score == 0.5:
                    feature.qualifiers['colour'] = 13 # light grey
            fid = feature_id(entry, feature)
            ft = {
                'fig': fid,
                'function': feature.function,
                'contig': entry.id,
                'start': feature.start,
                'stop': feature.stop,
                'rank': 0.0,
                'status': 0,
                'pp': pp_score,
            }

            x.append(ft)

    ranks = [[] for n in range(len(x))]
    for j, val in enumerate(self.rfdata):
        for k in range(j-int(self.window_size/2), j+int(self.window_size/2)):
            if k < 0 or k >= len(x) or j >= len(x) or x[k]['contig'] != x[j]['contig']:
                continue
            ranks[k].append(val)

    # calculate threshold
    y = []
    j = 0
    while j < len(x):
        x[j]['rank'] = sum(ranks[j]) / len(ranks[j])
        x[j]['extra'] = ranks[j]
        y.append(x[j]['rank'])
        j = j+1

    y2 = np.array(y).reshape(-1, 1)
    km = KMeans(n_clusters=2)
    km.fit(y2)
    centers = km.cluster_centers_
    threshold = max(centers[0][0], centers[1][0])
    log_and_message(f"Rank threshold calculated as {threshold}")
    """
    Note added by Rob:
    At this point we have the classifications for each ORF and we want to take a sliding window and decide where
    the phage should start. We have two calculations for a threshold for the rank: either the kmeans centers and
    finding things above the larger center or just a plain threshold.
    """

    """
    Eventually each row has:
        0. gene id           6. rank                12. start of attR
        1. function          7. my status           13. end of attR
        2. contig            8. pp                  14. sequence of attL
        3. start             9. final status        15. sequence of attR
        4. stop             10. start of attL       16. Reason for att site choice
        5. position         11. end of attL
    However, at this point we only have  0 .. 8
    """

    for i in range(len(x)):
        status = 1 if x[i]['rank'] > threshold else 0
        # for regions that are absolutely not prophages (esp. ribosomal proteins)
        # set the rank to 0. We should, perhaps, mark these as potentially mobile?
        if is_not_phage_func(x[i]['function']):
            x[i]['rank'] = 0
            status = 0
            x[i]['pp'] = 0
        thisrow = [
            x[i]['fig'],
            x[i]['function'],
            x[i]['contig'],
            x[i]['start'],
            x[i]['stop'],
            i,
            x[i]['rank'],
            status,
            x[i]['pp']
        ]
        data.append(thisrow)
    return data


import tensorflow as tf
import numpy as np
from DartDeep.dart_env_v2_1 import HpDartEnv
import pydart2
from itertools import count
from collections import deque
from random import random, sample
from multiprocessing import Process, Pipe
from copy import deepcopy

class Replay(deque):
    def sample(self, batch_size):
        return [self[i] for i in sample(range(0, len(self)), batch_size)]

class Episode(list):
    pass

class HpPPO(object):
    def __init__(self, session, env_name='walk', num_slaves=1):
        self.sess = session
        self.env = HpDartEnv(env_name)
        self.num_slaves = num_slaves

        self.num_state = self.env.observation_space.shape[0]
        self.num_action = self.env.action_space.shape[0]
        self.action_bound = [self.env.action_space.low, self.env.action_space.high]

        self.num_train = 0

        self.layer_size = [128, 64]
        self.error_mag = 0.1
        self.num_epoches = 10
        # self.sample_size = 256
        self.sample_size = 2048
        self.batch_size = 128
        self.gamma = 0.95
        self.td_lambda = 0.95
        self.clip_ratio = 0.2

        # set memory and episodes
        self.replay_buffer = Replay()
        self.total_episodes = list()  # type: list[Episode]

        # set varialbles
        with tf.variable_scope('state'):
            self.state = tf.placeholder(tf.float32, shape=[None, self.num_state])

        with tf.variable_scope('action'):
            self.action = tf.placeholder(tf.float32, shape=[None, self.num_action])

        with tf.variable_scope('target_value'):
            self.y = tf.placeholder(tf.float32, shape=[None, 1])

        with tf.variable_scope('advantages'):
            self.advantages = tf.placeholder(tf.float32, shape=[None, 1])

        # build networks
        self.value = self.build_value_net()
        self.actor, self.actor_param = self.build_actor_net('actor_net', trainable=True)
        self.actor_old, self.actor_old_param = self.build_actor_net('actor_old', trainable=False)
        self.syn_old_pi = [oldp.assign(p) for p, oldp in zip(self.actor_param, self.actor_old_param)]
        self.sample_op = tf.clip_by_value(tf.squeeze(self.actor.sample(1), axis=0), self.action_bound[0], self.action_bound[1])

        # set loss function
        with tf.variable_scope('critic_loss'):
            self.adv = self.y - self.value
            self.critic_loss = tf.reduce_mean(tf.square(self.adv))

        with tf.variable_scope('actor_loss'):
            ratio = self.actor.prob(self.action) / self.actor_old.prob(self.action)
            self.actor_loss = tf.reduce_mean(tf.minimum(ratio * self.advantages, tf.clip_by_value(ratio, 1. - self.clip_ratio, 1. + self.clip_ratio)))

        # set optimizer
        self.value_step_size = 1e-2
        self.value_optimizer = tf.train.AdamOptimizer(self.value_step_size)
        self.train_critic = self.value_optimizer.minimize(self.critic_loss)

        self.policy_step_size = 1e-4
        self.policy_optimizer = tf.train.AdamOptimizer(self.policy_step_size)
        self.train_policy = self.value_optimizer.minimize(self.actor_loss)

        # for evaluation
        self.num_eval = 0

        # for multiprocessing
        self.state_sender = []  # type: list[Connection]
        self.result_sender = []  # type: list[Connection]
        self.state_receiver = []  # type: list[Connection]
        self.result_receiver = []  # type: list[Connection]
        self.action_sender = []  # type: list[Connection]
        self.reset_sender = []  # type: list[Connection]
        self.motion_sender = []  # type: list[Connection]
        self.envs = []  # type: list[Process]

    def init_envs(self):
        for slave_idx in range(self.num_slaves):
            s_s, s_r = Pipe()
            r_s, r_r = Pipe()
            a_s, a_r = Pipe()
            reset_s, reset_r = Pipe()
            motion_s, motion_r = Pipe()
            p = Process(target=worker, args=(self.rnn_len, slave_idx, s_s, r_s, a_r, reset_r, motion_r))
            self.state_sender.append(s_s)
            self.result_sender.append(r_s)
            self.state_receiver.append(s_r)
            self.result_receiver.append(r_r)
            self.action_sender.append(a_s)
            self.reset_sender.append(reset_s)
            self.motion_sender.append(motion_s)
            self.envs.append(p)
            p.start()

    def envs_get_states(self, terminated):
        states = []
        for recv_idx in range(len(self.state_receiver)):
            if terminated[recv_idx]:
                states.append([0.] * self.num_state)
            else:
                states.append(self.state_receiver[recv_idx].recv())
        return states

    def envs_send_actions(self, actions, terminated):
        for i in range(len(self.action_sender)):
            if not terminated[i]:
                self.action_sender[i].send(actions[i])

    def envs_get_status(self, terminated):
        status = []
        for recv_idx in range(len(self.result_receiver)):
            if terminated[recv_idx]:
                status.append((0., True))
            else:
                status.append(self.result_receiver[recv_idx].recv())
        return zip(*status)

    def envs_resets(self, reset_flag):
        for i in range(len(self.reset_sender)):
            self.reset_sender[i].send(reset_flag)

    def envs_reset(self, i, reset_flag):
        self.reset_sender[i].send(reset_flag)

    def build_value_net(self):
        # build networks
        with tf.variable_scope('value_net'):
            value_dl1 = tf.contrib.layers.fully_connected(inputs=self.state,
                                                          num_outputs=self.layer_size[0],
                                                          activation_fn=tf.nn.relu,
                                                          scope='value_dl1')

            value_dl2 = tf.contrib.layers.fully_connected(inputs=value_dl1,
                                                          num_outputs=self.layer_size[1],
                                                          activation_fn=tf.nn.relu,
                                                          scope='value_dl2')

            value = tf.contrib.layers.fully_connected(inputs=value_dl2,
                                                      num_outputs=1,
                                                      activation_fn=None,
                                                      scope='value')

            return value

    def build_actor_net(self, scope, trainable):
        with tf.variable_scope(scope):
            actor_dl1 = tf.contrib.layers.fully_connected(inputs=self.state,
                                                          num_outputs=self.layer_size[0],
                                                          activation_fn=tf.nn.relu,
                                                          trainable=trainable,
                                                          scope='dl1')

            actor_dl2 = tf.contrib.layers.fully_connected(inputs=actor_dl1,
                                                          num_outputs=self.layer_size[1],
                                                          activation_fn=tf.nn.relu,
                                                          trainable=trainable,
                                                          scope='dl2')

            mu = tf.contrib.layers.fully_connected(inputs=actor_dl2,
                                                   num_outputs=self.num_action,
                                                   activation_fn=None,
                                                   trainable=trainable,
                                                   scope='mu')

            sigma = tf.contrib.layers.fully_connected(inputs=actor_dl2,
                                                      num_outputs=self.num_action,
                                                      activation_fn=tf.nn.softplus,
                                                      trainable=trainable,
                                                      scope='sigma')
            # sigma = tf.convert_to_tensor(0.1 * np.ones(self.num_action), dtype=np.float32)

            actor_dist = tf.contrib.distributions.Normal(loc=mu, scale=sigma)

            param = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope)

            return actor_dist, param

    def get_action(self, s):
        return self.sess.run(self.sample_op, feed_dict={self.state: s[np.newaxis, :]})

    def get_v(self, s):
        if s.ndim < 2:
            s = s[np.newaxis, :]
        return self.sess.run(self.value, feed_dict={self.state: s})[0, 0]

    def train(self):
        self.generate_transitions()
        self.optimize_model()
        self.num_train += 1

    def generate_transitions(self):
        del self.total_episodes[:]
        episodes = [Episode() for _ in range(self.num_slaves)]
        terminated = [False for _ in range(self.num_slaves)]

        self.env.Resets(True)
        # self.envs_resets(1)
        local_step = 0

        while True:
            states = self.env.GetStates()
            # states = self.envs_get_states(terminated)

            actions = np.asarray(self.get_action(states))
            values = self.get_v(states)
            logprobs = self.actor.prob(actions)

            # self.envs_send_actions(actions, terminated)
            # rewards, is_done = self.envs_get_status(terminated)

            __, reward, is_done, info = self.env.step(actions.flatten())
            rewards = [reward]
            is_dones = [is_done]
            for j in range(self.num_slaves):
                if terminated[j]:
                    continue

                nan_occur = np.any(np.isnan(states[j])) or np.any(np.isnan(actions[j]))
                if not nan_occur:
                    episodes[j].append((states[j], actions[j], rewards[j], values[j], logprobs[j]))

                if is_dones[j] or nan_occur:
                    self.total_episodes.append(deepcopy(episodes[j]))

                    if local_step < self.sample_size:
                        episodes[j] = Episode()
                        # self.envs_reset(j, 1)
                        self.env.reset()
                    else:
                        terminated[j] = True
                else:
                    # self.envs_reset(j, 0)
                    pass

            if local_step >= self.sample_size and all(terminated):
                break

    def optimize_model(self):
        self.compute_td_gae()

        for _ in range(self.num_epoches):
            transitions = self.replay_buffer.sample(self.batch_size)
            batch = list(zip(*transitions))

            td = batch[3]

            self.update_value()
            self.update_policy()

    def compute_td_gae(self):
        for epi in self.total_episodes:
            len_epi = len(epi)
            states, actions, rewards, values, logprobs = zip(*epi)

            values = np.concatenate((values, np.zeros(1)), axis=0)
            advantages = np.zeros(len_epi)
            ad_t = 0

            for i in reversed(range(len_epi)):
                delta = rewards[i] + values[i + 1] * self.gamma - values[i]
                ad_t = delta + self.gamma * self.td_lambda * ad_t
                advantages[i] = ad_t

            TD = values[:len_epi] + advantages
            for i in range(len_epi):
                self.replay_buffer.append((states[i], actions[i], logprobs[i], TD[i], advantages[i]))

    def update_value(self):
        pass

    def update_policy(self):
        pass

    def evaluate(self):
        self.num_eval += 1
        total_reward = 0
        total_step = 0
        self.env.Reset(False, 0)

        state = self.env.GetState(0)

        for t in count():
            action = np.asarray(self.actor.mean().eval(feed_dict={ppo.state: [state]})).flatten()
            state, reward, is_done, info = self.env.step(action)
            if is_done:
                break
            else:
                total_step += 1
                total_reward += reward

        # print('noise: {:.3f}'.format(self.actor.stddev().eval(feed_dict={ppo.state: [state]})))
        print('noise: ', self.actor.stddev().eval(feed_dict={ppo.state: [state]}))
        if total_step > 0:
            print('Epi reward : {:.2f}, Step reward : {:.2f} Total step : {}'
                       .format(total_reward, total_reward / total_step, total_step))
        else:
            print('bad')
        return total_reward, total_step

def worker(env_name, proc_num, state_sender, result_sender, action_receiver, reset_receiver, motion_receiver):
    """

    :type env_name: str
    :type proc_num: int
    :type result_sender: Connection
    :type action_receiver: Connection
    :return:
    """

    # reset variable
    # 0 : go on (no reset)
    # 1 : soft reset ( w/o motion change )
    # 2 : hard reset ( with motion change )

    env = HpDartEnv(env_name)

    state = None
    while True:
        reset_flag = reset_receiver.recv()
        if reset_flag == 1:
            state = env.reset()
        elif reset_flag == 2:
            goals, qs = motion_receiver.recv()
            env.update_target(goals, qs)
            state = env.reset()

        state_sender.send(state)
        action = action_receiver.recv()
        state, reward, is_done, _ = env.step(action)
        result_sender.send((reward, is_done))

if __name__ == '__main__':
    pydart2.init()
    with tf.Session() as sess:
        ppo = HpPPO(sess, 'walk')
        sess.run(tf.global_variables_initializer())
        # print(sigma.eval())
        # print(actor_dist.sample(1).eval(feed_dict={state: np.zeros((1, num_state))}))
        # print(ppo.actor.mean().eval(feed_dict={ppo.state: np.zeros((1, ppo.num_state))}))
        ppo.train()
        ppo.evaluate()


import numpy
from generate import *

def generate():
    def test_vector_wrapper(frames):
        template = "require('radio.blocks.protocol.idmframer').IDMFrameType.vector_from_array({%s})"
        return [template % (','.join(frames))]

    frame1_bits = numpy.array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0], dtype=numpy.bool_)
    frame1_object = "{0x04, 0x17, 13897632, 172, 188, \"\\x02\\x00\\x00\\x0f\\x08\\x00\", \"\\x00\\x00\", \"\\x00\\x00\\x00\\x00\\x00\\x00\", 1436228, \"\\x01\\x80\\x80\\x60\\x30\\x18\\x08\\x06\\x03\\x01\\x00\\xc0\\xa0\\x70\\x38\\x14\\x0c\\x06\\x01\\x01\\x00\\xa0\\x40\\x10\\x0c\\x08\\x04\\x02\\x01\\x00\\x80\\xa0\\x50\\x28\\x14\\x0a\\x05\\x02\\x41\\x20\\x90\\x48\\x28\\x12\\x09\\x04\\x82\\x41\\x20\\xa0\\x48\\x24\\x12\", 1390, 0x67bf, 0x791a}"

    frame2_bits = numpy.array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1], dtype=numpy.bool_)
    frame2_object = "{0x04, 0x17, 11278109, 247, 188, \"\\x02\\x01\\x00\\xef\\x09\\x00\", \"\\x00\\x00\", \"\\x00\\x00\\x00\\x00\\x00\\x00\", 339972, \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x40\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x04\\x00\", 1472, 0xeaba, 0x57af}"

    frame3_bits = numpy.array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1], dtype=numpy.bool_)
    frame3_object = "{0x04, 0x17, 1550406067, 34, 184, \"\\x00\\x05\\x00\\x0e\\x01\\x00\", \"\\x00\\x00\", \"\\x00\\x00\\x00\\x00\\x00\\x00\", 8231734, \"\\x07\\x83\\xc1\\xe1\\x00\\x68\\x48\\x22\\x11\\x07\\x83\\xc2\\x21\\x20\\x98\\x5c\\x36\\x18\\x08\\x84\\x42\\x41\\x20\\x80\\x3c\\x1c\\x17\\x09\\x85\\xc3\\x81\\x90\\xc0\\x60\\x20\\x13\\x0b\\x06\\x02\\x21\\x20\\x90\\x28\\x16\\x0c\\x06\\x03\\x41\\xa0\\xd0\\x70\\x34\\x26\", 2179, 0xeefa, 0xfd7d}"

    vectors = []

    x = numpy.hstack([random_bit(20), frame1_bits, random_bit(20)])
    vectors.append(TestVector([], [x], test_vector_wrapper([frame1_object]), "Valid frame 1"))

    x = numpy.hstack([random_bit(20), frame2_bits, random_bit(20)])
    vectors.append(TestVector([], [x], test_vector_wrapper([frame2_object]), "Valid frame 2"))

    x = numpy.hstack([random_bit(20), frame3_bits, random_bit(20)])
    vectors.append(TestVector([], [x], test_vector_wrapper([frame3_object]), "Valid frame 3"))

    x = numpy.hstack([random_bit(20), frame1_bits, random_bit(20)])
    x[160] = not x[160]
    vectors.append(TestVector([], [x], test_vector_wrapper([frame1_object]), "Frame 1 with message bit error"))

    x = numpy.hstack([random_bit(20), frame2_bits, random_bit(20)])
    x[748] = not x[748]
    vectors.append(TestVector([], [x], test_vector_wrapper([frame2_object]), "Frame 2 with crc bit error"))

    x = numpy.hstack([random_bit(20), frame1_bits, random_bit(20), frame2_bits, random_bit(20), frame3_bits, random_bit(20)])
    vectors.append(TestVector([], [x], test_vector_wrapper([frame1_object, frame2_object, frame3_object]), "Three frames"))

    return BlockSpec("IDMFramerBlock", vectors, 1e-6)


# -*- coding: utf-8 -*-
"""
@Project:   pytorch-train
@File   :   DCGAN_CAN
@Author :   TonyMao@AILab
@Date   :   2020/1/16
@Desc   :   None
"""

import torch

from models.CANx256 import CANGenerator, CANDiscriminator
from models.CANx64 import Generator, Discriminator, nz
from models.blocks.gradient_penalty import calculate_gradient_penatly
from models.helpers import init_weights

class CANModel:
    def __init__(self, opt):
        self.name = 'Creative Adversarial Network'
        self.opt = opt

        self.is_train = True
        self.batch_size = opt.batchSize
        self.gpu_ids = opt.gpu_ids if opt.gpu_ids else []
        self.device = torch.device("cuda:0" if (torch.cuda.is_available() and len(self.gpu_ids) > 0) else "cpu")
        self.dtype = torch.cuda.FloatTensor if self.device != torch.device("cpu") else torch.FloatTensor
        self.save_dir = opt.expr_dir
        if self.opt.fine_size == 256:
            self.discriminator = CANDiscriminator(opt.channel, num_class=2).to(self.device)
            self.generator = CANGenerator(latent_dim=opt.latent_dim, hidden=opt.hidden).to(self.device)
            self.fixed_noise = torch.randn(self.batch_size, self.opt.latent_dim, 1, 1).to(self.device)
        elif self.opt.fine_size == 64:
            self.discriminator = Discriminator(0)
            self.generator = Generator(0, u="up+conv")
            self.fixed_noise = torch.randn((self.batch_size, nz, 2, 2)).to(self.device)
        else:
            self.discriminator = Discriminator(0)
            self.generator = Generator(0, u="up+conv")
            self.fixed_noise = torch.randn((self.batch_size, nz, 2, 2)).to(self.device)
            # raise Exception("not support size")
        self.optimizer_D = torch.optim.Adam(self.discriminator.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
        self.optimizer_G = torch.optim.Adam(self.generator.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
        # self.schedular_D = get_scheduler(self.optimizer_D, opt)
        # self.schedular_G = get_scheduler(self.optimizer_G, opt)
        self.time_g = 10
        self.time_d = 10

        init_weights(self.discriminator)
        init_weights(self.generator)
        self.cuda()

    def cuda(self):
        self.discriminator.type(self.dtype)
        self.generator.type(self.dtype)

    def gen_random_noise(self, current_minibatch):
        random_noise = None
        if self.opt.fine_size == 256:
            random_noise = torch.randn((current_minibatch, self.opt.latent_dim, 1, 1)).to(self.device)
        elif self.opt.fine_size == 64:
            # random_noise = torch.randn((current_minibatch, nz, 1, 1)).to(self.device)
            random_noise = torch.softmax(torch.randn((current_minibatch, nz * 4)), dim=1).to(self.device)
            random_noise = random_noise.view((current_minibatch, nz, 2, 2))
        return random_noise

    def train_batch(self, inputs: dict, loss: dict, metrics: dict, niter: int = 0) -> dict:
        real = inputs["Source"].type(self.dtype)
        # real_label = inputs["Class"].type(self.dtype)
        # fake_label = torch.zeros((self.batch_size,), device=self.device).type(self.dtype)

        current_minibatch = real.shape[0]
        label = torch.full((current_minibatch,), 1).to(self.device)
        err_d_sum = 0
        self.optimizer_D.zero_grad()

        err_d = 0
        for _ in range(self.time_d):
            # train with real label for D
            random_noise = self.gen_random_noise(current_minibatch)
            fake = self.generator(random_noise)
            pred_real = self.discriminator(real)
            pred_fake = self.discriminator(fake)
            label.fill_(1)
            gradient_penalty = calculate_gradient_penatly(self.discriminator, real.data, fake.data, self.device)
            err_d_real = loss["bce_loss"](pred_real, label) + gradient_penalty
            err_d_real.backward(retain_graph=True)
            label.fill_(0)
            err_d_fake = loss["bce_loss"](pred_fake, label)
            err_d_fake.backward()
        self.optimizer_D.step()
        err_d_mean = err_d / self.time_d
        # for _ in range(self.time_g):

        self.optimizer_G.zero_grad()
        random_noise = self.gen_random_noise(current_minibatch)
        fake = self.generator(random_noise)
        pred_fake = self.discriminator(fake)
        label.fill_(0)
        err_g = loss["bce_loss"](pred_fake, label)
        # err_g = - torch.mean(pred_fake)
        err_g.backward()
        self.optimizer_G.step()

        with torch.no_grad():
            fake = self.generator(self.fixed_noise)

        return {
            "vis": {"Target": fake,
                    "Source": inputs["Source"]},
            "loss": {"Loss_G": err_g,
                     "Loss_D": err_d_mean,
                     # "D_fake": float(err_d_fake.mean().item()),
                     # "D_real": float(err_d_real.mean().item()),
                     # "Time_G": self.time_g
                     }
        }

if __name__ == '__main__':
    model = Generator(0, "up+conv")
    random_noise = torch.randn((10, nz, 1, 1))
    res = model(random_noise)
    print(res.shape)

    """
    import matplotlib.pyplot as plt
    import numpy as np
    torch.random.manual_seed(np.random.random(1))
    generator = CANGenerator(latent_dim=100, hidden=1024, norm_layer=nn.BatchNorm2d)
    discriminator = CANDiscriminator(in_channel=3, num_class=2, norm_layer=nn.BatchNorm2d)
    init_weights(generator, "normal")
    init_weights(discriminator, "normal")
    z = torch.rand((2, 100))
    print(z.shape)
    y = generator(z)
    y_data = (y.detach().numpy()[0].transpose([1, 2, 0]) + 1) * 128
    plt.imshow(np.array(y_data, dtype='uint8'))
    plt.show()
    y_data = (y.detach().numpy()[1].transpose([1, 2, 0]) + 1) * 128
    plt.imshow(np.array(y_data, dtype='uint8'))
    plt.show()
    cv2.imwrite("test1.png", np.array(y_data, dtype='uint8'))
    fake = (torch.rand((3, 256, 256)))
    y_data = (fake.detach().numpy().transpose([1, 2, 0])) * 255
    plt.imshow(np.array(y_data, dtype='uint8'))
    cv2.imwrite("test1.png", np.array(y_data, dtype='uint8'))
    plt.show()
    res = discriminator(y)
    predict = torch.softmax(res, dim=-1)
    print(predict)
"""


import numpy as np
from scipy.special import ellipk, ellipe
from scipy.constants import mu_0

import properties

from discretize.base import BaseMesh
from discretize import TensorMesh

from ...utils import mkvc

def MagneticDipoleVectorPotential(
    srcLoc, obsLoc, component, moment=1.0, orientation=np.r_[0.0, 0.0, 1.0], mu=mu_0
):
    """
    This code has been deprecated after SimPEG 0.11.5. Please use geoana instead. "

    .. code::

        >> pip install geoana
        >> from geoana.electromagnetics.static import MagneticDipoleWholeSpace
    """

    raise Exception(
        "This code has been deprecated after SimPEG 0.11.5. "
        "Please use geoana instead. "
        "\n >> pip install geoana "
        "\n >> from geoana.electromagnetics.static import MagneticDipoleWholeSpace"
    )

def MagneticDipoleFields(
    srcLoc, obsLoc, component, orientation="Z", moment=1.0, mu=mu_0
):
    """
    This code has been deprecated after SimPEG 0.11.5. Please use geoana instead. "

    .. code::

        >> pip install geoana
        >> from geoana.electromagnetics.static import MagneticDipoleWholeSpace
    """

    raise Exception(
        "This code has been deprecated after SimPEG 0.11.5. "
        "Please use geoana instead. "
        "\n >> pip install geoana "
        "\n >> from geoana.electromagnetics.static import MagneticDipoleWholeSpace"
    )

def MagneticLoopVectorPotential(
    srcLoc, obsLoc, component, radius, orientation="Z", mu=mu_0
):
    """
    This code has been deprecated after SimPEG 0.11.5. Please use geoana instead. "

    .. code::

        >> pip install geoana
        >> from geoana.electromagnetics.static import MagneticDipoleWholeSpace
    """

    raise Exception(
        "This code has been deprecated after SimPEG 0.11.5. "
        "Please use geoana instead. "
        "\n >> pip install geoana "
        "\n >> from geoana.electromagnetics.static import CircularLoopWholeSpace"
    )


import config as cfg
import cv2
import numpy as np
from keras.models import load_model
from keras.preprocessing.image import img_to_array
from keras import backend as K
import tensorflow as tf
import keras

'''
esto es necesario para que no haya errores a la hora de exponer el servicio con flask
info --> https://github.com/tensorflow/tensorflow/issues/28287#issuecomment-495005162
'''
from keras.backend import set_session
sess = tf.Session()
graph = tf.get_default_graph()

set_session(sess)
model_emotions = load_model(cfg.path_model)

class predict_emotions():
    '''
    def __init__(self):
        # cargo modelo de deteccion de emociones
        global graph
        self.graph = tf.get_default_graph()
        self.model_emotions = load_model(cfg.path_model)
    '''

    def preprocess_img(self,face_image,rgb=True,w=48,h=48):
        face_image = cv2.resize(face_image, (w,h))
        if rgb == False:
            face_image = cv2.cvtColor(face_image, cv2.COLOR_BGR2GRAY)
        face_image = face_image.astype("float") / 255.0
        face_image= img_to_array(face_image)
        face_image = np.expand_dims(face_image, axis=0)
        return face_image

    def get_emotion(self,img,boxes_face):
        emotions = []
        if len(boxes_face)!=0:
            for box in boxes_face:
                y0,x0,y1,x1 = box
                face_image = img[x0:x1,y0:y1]
                # preprocesar data
                face_image = self.preprocess_img(face_image ,cfg.rgb, cfg.w, cfg.h)
                # predecir imagen
                global sess
                global graph
                with graph.as_default():
                    set_session(sess)
                    prediction = model_emotions.predict(face_image)
                    emotion = cfg.labels[prediction.argmax()]
                    emotions.append(emotion)
        else:
            emotions = []
            boxes_face = []
        return boxes_face,emotions


import sys, os, time
import wave
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, LSTM
from keras.layers.convolutional import Conv1D, MaxPooling1D
from keras.layers.embeddings import Embedding
from keras.preprocessing import sequence
from keras.utils import np_utils
from bottle import Bottle, route, run, request, response, BaseRequest
import json

app = Bottle()
BaseRequest.MEMFILE_MAX = 1024000000

def pre():
	return "hello client!"

def predict(data):

	name = data['name']
	syllable = data['syllable']
	prediction_model_file = "C:\\jython\\Pronunciation\\Pronunciation-Matching\\main\\python\\H5\\" + name + ".h5"
	prediction_model_file = "C:\\jython\\Pronunciation\\Pronunciation-Matching\\main\\python\\H5\\" + "Bag" + ".h5"

	SAMPLE_RATE = 44100
	CHUNK_SIZE = 1024

	no_of_files = 15
	training_percentage = 0.7
	sequence_length = 50
	embedding_vecor_length = 32

	model = Sequential()
	model.add(Embedding(50, embedding_vecor_length, input_length=sequence_length))
	model.add(Conv1D(filters=32, kernel_size=3, padding='same', activation='relu'))
	model.add(MaxPooling1D(pool_size=2))
	model.add(LSTM(100))
	model.add(Dense(2, activation='softmax'))
	model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
	model.load_weights(prediction_model_file)

	s_array = np.asarray(syllable)
	s_array_new = np.reshape(s_array, (-1, 1))
	s_use = np.transpose(s_array_new)

	predictions = model.predict(s_use)

	true = predictions[0][0]*100
	false = predictions[0][1]*100
	return true

@app.hook('after_request')
def enable_cors():
	response.headers['Access-Control-Allow-Origin'] = '*'
	response.headers['Access-Control-Allow-Methods'] = 'PUT, GET, POST, DELETE, OPTIONS'
	response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'

@app.route('/')
def hello():
	return 'Hello World!'

@app.route('/api/test', method=['OPTIONS', 'POST'])
def apitest():
	if request.method == 'POST':
		data = request.json
		print(type(data))
		print(data)
		res = {"true": predict(data)}
		return res
	else:
		return 'ok'

app.run(port=5000, debug=True)


#@title
import torch
from torch.autograd import Variable
from torch.utils.data import Dataset, DataLoader
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR
from torchvision import datasets, transforms, models
from torchvision.datasets import ImageFolder
import torchvision.models as models
import numpy as np
import cv2
from PIL import Image
import os

# classes = ['pinghe', 'qixu', 'qiyu', 'shire', 'tanshi', 'xueyu', 'yangxu', 'yinxu']
WIDTH, HEIGHT=350,350

def getResult(filePath):
    # 环境
    # use_cuda = not no_cuda and torch.cuda.is_available()
    use_cuda = torch.cuda.is_available()
    device = torch.device("cuda" if use_cuda else "cpu")

    normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    preprocess = transforms.Compose([transforms.ToTensor(), normalize])
    img_pil = Image.open(filePath)
    img_pil = img_pil.resize((WIDTH, HEIGHT),Image.ANTIALIAS)
    img = preprocess(img_pil)
    img = img.unsqueeze(0)
    img = img.to(device)

    #读模型参数
    # model = models.resnet18(pretrained=True)
    # model.fc = nn.Linear(512,8)
    # model=model.to(device)
    # model.load_state_dict(torch.load(model_path))
    # model.eval()

    # #读整个模型
    model=(torch.load('RecWholeModel_5.pt'))
    model=model.to(device)
    model.eval()

    with torch.no_grad():
      py = model(img)
    # print(py)

    py = F.softmax(py,1)
    confidence = py.numpy()

    return confidence[0]#返回置信度进行加权

    # print(py)

    '''
    res,predicted = torch.max(py, 1)  # 获取分类结果
    predicted = predicted.numpy()
    classIndex = predicted[0]
    res = res.numpy() #将tensor转换成numpy，再取出置信度的int
    rate = res[0]
    # print(rate,classIndex)
    return res,predicted
    '''
    # return rate,classIndex

    # print("置信度:",rate)
    # print("种类:",classIndex)
    # print('预测结果：类{} {}'.format(classIndex, class_name[classIndex]))

# predict(model_path,img_path,classes)


import torch
import itertools
from util.image_pool import ImagePool
from .base_model import BaseModel
from . import networks
from torch.autograd import Variable
import numpy as np
from .dltk_model import DLTKModel
import os

class CycleGAN225Model(BaseModel):

    def name(self):
        return 'CycleGAN 2_25 model'

    def modify_commandline_options(parser, is_train=True):
        parser.set_defaults(no_dropout=True)  # default CycleGAN did not use dropout
        if is_train:
            parser.add_argument('--init_D', type=str, default=None, help='initialization for netD')
            parser.add_argument('--init_G', type=str, default=None, help='initialization for netG')
            parser.add_argument('--dltk_CLS', type=str, default=None, help='folder for dltk classification model', required=True)
            parser.add_argument('--lambda_CLS', type=float, default=0.1, help='weight for classification loss (KL-divergence)')

    def load_single_network(self, net, pth):
        state_dict = torch.load(pth, map_location=str(self.device))
        if hasattr(state_dict, '_metadata'):
            del state_dict._metadata
        # patch InstanceNorm checkpoints prior to 0.4
        # for key in list(state_dict.keys()):
            # self.__patch_instance_norm_state_dict(state_dict, net, key.split('.'))
        net.module.load_state_dict(state_dict)
        return net

    def setup(self, opt):
        super(CycleGAN225Model, self).setup(opt)
        if self.isTrain:
            if not opt.init_D is None:
                print('initializing discriminator network from %s' % opt.init_D)
                self.netD = self.load_single_network(self.netD, opt.init_D).cuda()
            if not opt.init_G is None:
                print('initializing generator network from %s' % opt.init_G)
                self.netG = self.load_single_network(self.netG, opt.init_G).cuda()

    def __init__(self, opt):

        BaseModel.__init__(self, opt)
        self.loss_names = ['D', 'G', 'sem']
        self.visual_names = ['real_A', 'fake_B']
        if self.isTrain:
            self.model_names = ['G', 'D', 'CLS']
        else:
            self.model_names = ['G']
        self.AtoB = opt.direction == 'AtoB'
        self.lambda_CLS = opt.lambda_CLS

        input_nc,output_nc = (opt.input_nc,opt.output_nc) if self.AtoB else (opt.output_nc,opt.input_nc)
        self.netG = networks.define_G(input_nc, output_nc, opt.ngf, opt.netG, opt.norm,
                                    not opt.no_dropout, opt.init_type, opt.init_gain, self.gpu_ids)
        # self.netG = torch.nn.DataParallel(self.netG)
        if self.isTrain:
            self.netD = networks.define_D(output_nc, opt.ndf, opt.netD,
                                    opt.n_layers_D, opt.norm, opt.init_type, opt.init_gain, self.gpu_ids)
            # self.netD = torch.nn.DataParallel(self.netD)
            # self.netCLS = parse_dltk_model(opt.dltk_CLS)
            print('initializing classification network from %s' % opt.dltk_CLS)
            self.netCLS = torch.nn.DataParallel(DLTKModel(opt.dltk_CLS)).cuda()

        if self.isTrain:
            self.fake_pool = ImagePool(opt.pool_size)
            self.criterionGAN = networks.GANLoss(opt.gan_mode).to(self.device)
            self.criterionCLS = torch.nn.KLDivLoss().to(self.device)
            self.optimizer_G = torch.optim.Adam(self.netG.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
            self.optimizer_D = torch.optim.Adam(self.netD.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
            self.optimizers.append(self.optimizer_G)
            self.optimizers.append(self.optimizer_D)

    def set_input(self, input):

        self.real_A = input['A' if self.AtoB else 'B'].to(self.device)
        self.real_B = input['B' if self.AtoB else 'B'].to(self.device)
        self.image_paths = input['A_paths' if self.AtoB else 'B_paths']

    def forward(self):
        self.fake_B = self.netG(self.real_A)
        if self.isTrain:
            self.pred_real_A = self.netCLS(self.real_A)
            self.pred_fake_B = self.netCLS(self.fake_B)

    def backward_D_basic(self, netD, real, fake):
        # Real
        pred_real = netD(real)
        loss_D_real = self.criterionGAN(pred_real, True)
        # Fake
        pred_fake = netD(fake.detach())
        loss_D_fake = self.criterionGAN(pred_fake, False)
        # Combined loss
        loss_D = (loss_D_real + loss_D_fake) * 0.5
        # backward
        loss_D.backward()
        return loss_D

    def backward_D(self):
        fake_B = self.fake_pool.query(self.fake_B)
        self.loss_D = self.backward_D_basic(self.netD, self.real_B, fake_B)

    def backward_G(self):
        self.loss_G = self.criterionGAN(self.netD(self.fake_B), True)
        self.loss_sem = 0.0
        for prA,pfB in zip(self.pred_real_A, self.pred_fake_B):
            self.loss_sem += self.criterionCLS(prA.log(), pfB)
        self.loss_sem /= len(self.pred_real_A)
        self.loss_G = self.loss_G + self.lambda_CLS*self.loss_sem
        self.loss_G.backward()

    def optimize_parameters(self):
        # forward
        self.forward()
        # G
        self.set_requires_grad([self.netD], False)
        self.set_requires_grad([self.netG], True)
        self.optimizer_G.zero_grad()
        self.backward_G()
        self.optimizer_G.step()
        # D
        self.set_requires_grad([self.netD], True)
        self.optimizer_D.zero_grad()
        self.backward_D()
        self.optimizer_D.step()


from darkflow.net.build import TFNet
import cv2
import pytesseract
import PIL
import numpy as np
from math import sqrt
import re
import datetime
from sqlalchemy import create_engine

def clean_entry(txt):
    txt = txt.replace(' ', '')
    pattern = r'[A-Za-z0-9]+'
    txt = re.findall(pattern, txt)
    txt = ''.join(txt)
    real_plate = 'N'
    if len(txt) >= 6:
        if txt[-3:].isdigit():
            plate_pos = txt
            if txt[:2].isalpha():
                real_plate = txt
                real_plate = re.sub(r'[a-z]', '', real_plate)
                print('MATCHED CRITERIA ', real_plate, '\n\n')
    if len(real_plate) >= 6:
        confirmed_plate = real_plate
    else:
        confirmed_plate = 'N'
    return confirmed_plate

def crop_plate(result, frame):
    if result is not None:
        print('NUM PLATES FOUND IS ', len(result))
    result_dict = result[0]
    label = result_dict['label']
    confidence = result_dict['confidence']
    tl_dict = result_dict['topleft']
    br_dict = result_dict['bottomright']
    x_tl = tl_dict['x']
    y_tl = tl_dict['y']
    x_br = br_dict['x']
    y_br = br_dict['y']
    with_rect = cv2.rectangle(frame, (x_tl, y_tl), (x_br, y_br), (0, 255, 0), 2)
    crop_img = frame[y_tl:y_br, x_tl:x_br]
    if len(result) > 1:
        result_dict = result[1]
        label = result_dict['label']
        confidence2 = result_dict['confidence']
        tl_dict = result_dict['topleft']
        br_dict = result_dict['bottomright']
        x_tl = tl_dict['x']
        y_tl = tl_dict['y']
        x_br = br_dict['x']
        y_br = br_dict['y']
        with_rect = cv2.rectangle(with_rect, (x_tl, y_tl), (x_br, y_br), (255, 255, 0), 2)
    return crop_img, confidence, x_tl, y_tl, x_br, y_br, label, with_rect

def display_lines(image, lines):
    line_image = np.zeros_like(image)
    line_length = []
    coordinates = []
    if lines is not None:
        for line in lines:
            x1, y1, x2, y2 = line.reshape(4)
            xdif = abs(x1 - x2)
            ydif = abs(y1 - y2)
            length = sqrt(xdif**2 + ydif**2)
            if abs(y1 - y2) > 4:
                line_length.append(length)
                coordinates.append((x1, y1, x2, y2))
                cv2.line(line_image, (x1, y1), (x2, y2), (0, 0, 255), 2)
        if len(line_length) > 0:
            m = max(line_length)
            index = [i for i, j in enumerate(line_length) if j == m]
            x1, y1, x2, y2 = coordinates[index[0]]
            cv2.line(line_image, (x1, y1), (x2, y2), (0, 255, 0), 2)
            slope = (y1 - y2) / (x1-x2)
            rot_rad = np.arctan(slope)
            rot_deg = rot_rad * (180/np.pi)
        else:
            rot_deg = 0
            line_image = image
        return line_image, rot_deg

def pre_process(img):
    lane_image = np.copy(img)
    gray = cv2.cvtColor(lane_image, cv2.COLOR_RGB2GRAY)
    canny = cv2.Canny(gray, 100, 150)
    hough = cv2.HoughLinesP(canny, 2, np.pi/180, 80, np.array([]), minLineLength=30, maxLineGap=5)
    if hough is not None:
        with_lines, rot_deg = display_lines(lane_image, hough)
        combo_image = cv2.addWeighted(lane_image, 0.8, with_lines, 1, 1)
        (h, w) = with_lines.shape[:2]
        center = (w / 2, h / 2)
        scale = 1
        M = cv2.getRotationMatrix2D(center, rot_deg-1, scale)
        rotated = cv2.warpAffine(lane_image, M, (w, h))
        enlarged = cv2.resize(rotated, None, fx=3, fy=3)
    else:
        rotated = lane_image
    return rotated

def read_plate(img):
    config = ("-l eng --oem 1 --psm 7")
    txt = pytesseract.image_to_string(img, config=config)
    return txt

def high_mention(rp):
    high_mention = []
    da_plates = [a for a, b in rp]
    unique_plates = set(da_plates)
    plate_count = [(da_plates.count(plate), plate) for plate in unique_plates]
    for amount, plate in plate_count:
        if amount >= 2:
            high_mention.append(plate)
    string_of_plates = ' '.join(high_mention)
    text_file = open("found_plates.txt", "w")
    text_file.write(string_of_plates)
    text_file.close()
    return high_mention

def full_recognition(video, tfnet, p, rp=[]):
    check, frame = video.read()
    key = cv2.waitKey(1)
    result = tfnet.return_predict(frame)
    crop_img = frame
    with_rect = frame
    text_over = frame
    show = frame
    b = 'N'
    if len(result) >= 1:
        crop_img, confidence, x_tl, y_tl, x_br, y_br, label, show = crop_plate(result, frame)
        if confidence >= 0.6:
            processed = pre_process(crop_img)
            cv2.imshow('pro', processed)
            p = p + 1
            cv2.waitKey(10)
            txt = read_plate(processed)
            if len(txt) >= 5:
                plate = clean_entry(txt)
            else:
                plate = 'N'
            if len(plate) >= 5:
                b = (plate, confidence)
                rp.append(b)
    show = cv2.resize(show, (1280, 720), fx=0, fy=0, interpolation=cv2.INTER_CUBIC)
    font = cv2.FONT_HERSHEY_SIMPLEX
    bottomLeftCornerOfText = (90, 700)
    fontScale = 1
    fontColor = (0, 255, 0)
    lineType = 2
    if len(rp) >= 1:
        show = cv2.putText(show, f'plate found with id: {rp[-1]}',
                           bottomLeftCornerOfText,
                           font,
                           fontScale,
                           fontColor,
                           lineType)
    return show, key, b, p

def send_to_db(plate):
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    sql = f"INSERT INTO plates (plate, seenat) VALUES ('{plate}', '{now}');"
    db.execute(sql)
    return (print(f'Entered {plate} into Database'))

def clear_db(db):
    sql = f"DELETE from plates"
    db.execute(sql)


#(0=Angry, 1=Fear, 2=Happy, 3=Sad, 4=Surprise, 5=Neutral)
import numpy as np
import cv2
import keras.models
import keras
import glob
from numpy import array
import imutils
import sys
import cv2

# load json and create model
json_file = open('../training/modelgenerated.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = keras.models.model_from_json(loaded_model_json)
# load weights into new model
loaded_model.load_weights("../training/modelgenerated.h5")
print("Loaded model from disk")

# using the model to generated emojis on live faces

loaded_model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

#using haarcascade
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

cap = cv2.VideoCapture(0)
roi_gray=[]
emoji=[]
pop=0
pr=0
while 1:
    ret, img = cap.read()

    #Creating GreyScale Image
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)
    center=0
    for (x,y,w,h) in faces:
        if(w>h):
            big=w
        else:
            big=h
        cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
        roi_gray = gray[y:y+h, x:x+w]
        roi_color = img[y:y+h, x:x+w]
        if(pop==1):
            emoji=cv2.imread("TempImg.jpg")
            emoji= cv2.resize(emoji,(w,h))
            #print(img[y:y+h,x:x+w])
            img[y:y+h,x:x+w]= emoji
            #print(emoji)
    k = cv2.waitKey(30) & 0xff
    if(k== 13):
        #Detecting Emotion on pressing enter key

        temp = cv2.resize(roi_gray,(48,48))
        cv2.imwrite("TempImg.jpg",roi_color)
        cv2.imwrite("facehai.jpg",temp)
        temp= cv2.imread("facehai.jpg")
        temp= temp/255
        pr=loaded_model.predict_classes(temp.reshape(1,48,48,3))
        #setting flag pop to 1
        pop=1

    img = imutils.resize(img, width=1280)
    cv2.imshow('img',img)

    #Stopping Excecution on escape key
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()