""" Northwestern MSiA 490-30 Project code, Spring 2016
    This code demonstrates the use of transfer learning to speed up
    the training process for a convolutional neural network.
    author: Kedi Wu, Luyao Yang, Yilei Li, Yung Jen Kung
"""
import os, numpy as np, random, time
import csv
from keras.optimizers import SGD, RMSprop, Adagrad, Adam

# Base settings
basepath = "train_crop_64"
outpath  = "predictions"
epoch_size = 8000
test_size  = 2000
imnorm   = 1.0          # Image normalization factor

batch_size, nb_epoch = 32, 100

# User tweakable settings
cnnlayers     = 4        # Total groups of CNN layers to create
vggxfer       = False     # Enables VGG weight transfer
vgglayers     = 2        # Number of first layers to load VGG weights into
freeze_conv   = True     # Freeze convolutional layers
fclayersize   = 512      # Size of fully connected layers
fclayers      = 1        # Number of fully connected layers
fcdropout     = 0.5      # Dropout factor for fully connected layers
normalize     = True     # Normalize input to zero mean
batchnorm     = True     # Batch normalization
loadmodel     = True     # Save/load models to reduce training time
savemodel     = True     # Save/load models to reduce training time
grid_size     = 3        # Combine this many photos into each
vis_filter    = False    # Show filter viz?
label_num     = 3        # how many labels to train

optimizer = Adagrad() #SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
#%% Load train data
def load_link(path):
    with open(path) as linkfile:
        reader = csv.reader(linkfile)
        mydict = {row[0]:[row[i+2] for i in range(label_num)] for row in reader}
    return mydict

def load_group(path):
    mydict = {}
    with open(path) as linkfile:
        reader = csv.reader(linkfile)
        for row in reader:
            key = row[1]
            if key in mydict:
                mydict[key].append(row[0])
            else:
                mydict[key] = [row[0]]
    return mydict

def load_data(basepath, reference, restaurant, number=4000, grid_size=3):
    """Loads image data using folder names as class names
       Beware: make sure all images are the same size, or resize them manually"""
    import scipy.misc
    xdata, ydata = [], [[] for i in range(label_num)]
    obj_classes = [ ["Not Good for Lunch", "Good for Lunch"],
                    ["Not Good for Dinner", "Good for Dinner"],
                    ["Not Take Reservation", "Take Reservation"]]
    unitkeys = list(restaurant.keys())
    unit = [random.choice(unitkeys) for i in range(number)]
    for business in unit:
        if len(restaurant[business]) < (grid_size**2): continue
        photo_ids = random.sample(restaurant[business], grid_size**2)
        images = [scipy.misc.imread(os.path.join(basepath, photo + '.jpg')) \
            for photo in photo_ids]
        #images = [np.swapaxes(im, 0, 2) for im in images]
        rows = []
        for i in range(grid_size):
            rows.append(np.hstack(images[(i*grid_size):(i*grid_size+3)]))
        combined = np.vstack(rows)
        combined = np.swapaxes(combined, 0, 2)

        xdata.append(combined)
        [ydata[i].append(reference[photo_ids[0]]) for i in range(label_num)]
        if int(time.time()*1000) % 250 == 0:
            print("Progress: " + str(len(xdata)) + " shape= " + str(combined.shape), end='\r')

    print("Loaded %d samples" % len(xdata))
    shuffle_ind = list(range(len(xdata)))
    random.shuffle(shuffle_ind)
    return np.array(xdata, dtype='float32')[shuffle_ind] / imnorm, np.array(ydata, dtype='float32')[shuffle_ind], obj_classes

# Load test data
reference = load_link("train_photo_linked.csv")
units = load_group("train_photo_linked.csv")
from keras.utils import np_utils
X_test, y_test, obj_classes = load_data(basepath, reference, units, test_size, grid_size)
if normalize:
    X_test = X_test - X_test.mean()
    X_test = X_test / X_test.std()
img_channels, img_rows, img_cols = X_test.shape[1:]
Y_test  = [np_utils.to_categorical(y_test[i], len(obj_classes[i])) for i in range(label_num)]

#%% Define a VGG-compatible model
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.convolutional import Convolution2D, MaxPooling2D, ZeroPadding2D
from keras import backend as K

model = Sequential()

# This layer is used for visualizing filters. Don't remove it.
model.add(ZeroPadding2D((1, 1), batch_input_shape=(1, 3, img_rows, img_cols)))
first_layer = model.layers[-1]
input_img = first_layer.input

# VGG net definition starts here. Change the cnnlayers to set how many layers to transfer
if cnnlayers >= 1:
    model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1', input_shape=(img_channels, img_rows, img_cols)))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_2'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))
    model.add(ZeroPadding2D((1, 1)))

if cnnlayers >= 2:
    model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_2'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))
    model.add(ZeroPadding2D((1, 1)))

if cnnlayers >=3:
    model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_2'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_3'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))
    model.add(ZeroPadding2D((1, 1)))

if cnnlayers >= 4:
    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_3'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))
    model.add(ZeroPadding2D((1, 1)))

if cnnlayers >= 5:
    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_2'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_3'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))

# VGG net definition ends here
# All layers past this convert the VGG convolutional "code" into a classification

# Flatten and normalize data here, we don't know the data distribution of
# the preloaded training weights, so batch normalization helps fix slowdowns
model.add(Flatten())
from keras.layers.normalization import BatchNormalization
if batchnorm: model.add(BatchNormalization())

submodels = []
for i in range(label_num):
    submodel = Sequential()
    submodel.add(model)
    for l in range(1, fclayers + 1):
        submodel.add(Dense(fclayersize, name='fc%d' % l))
        submodel.add(Activation('relu'))
        submodel.add(Dropout(fcdropout)) # Modify dropout as necessary

    if batchnorm: submodel.add(BatchNormalization())
    submodel.add(Dense(len(obj_classes)))
    submodel.add(Activation('softmax'))
    submodel.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])
    submodels.append(submodel)

#%% Load existing VGG weights
if vggxfer:
    weights_file = "vgg16_weights.h5" # Pretrained VGG weights
    if os.path.exists(weights_file):
        print("Found existing weights file, loading data...")
        import h5py
        f = h5py.File(weights_file)
        if 'layer_names' in f.attrs.keys(): print("Weights file has:", f.attrs['layer_names'])
        for k in range(f.attrs['nb_layers']):
            if k >= len(model.layers) or 'conv' not in model.layers[k].name:
                #print("Skipping layer:", k, model.layers[k].name if k < len(model.layers) else "<none>")
                # Commented layers are skipped
                continue
            # only load requested number of layers
            if int(model.layers[k].name[4]) > vgglayers:
                continue
            print("Transferring layer:", k, model.layers[k].name, model.layers[k].output_shape)
            g = f['layer_{}'.format(k)]
            weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]

            model.layers[k].set_weights(weights)

            if freeze_conv and int(model.layers[k].name[4]) <= vgglayers:
                model.layers[k].trainable = False
        f.close()

# Print model summary
model.summary()
print("Trainable layers:", model.trainable_weights)

#%% Visualization code
import matplotlib.pyplot as plt
layer_dict = dict([(layer.name, layer) for layer in model.layers])

def deprocess_image(x):
    x -= x.mean()
    x /= (x.std() + 1e-5)
    x = x*0.1 + 0.5
    x = np.clip(x, 0, 1) * 255
    x = x.transpose((1, 2, 0))
    x = np.clip(x, 0, 255).astype('uint8')
    return x

def viz_filter_max(layer_name, filter_index=0, max_steps=150):
    layer_output = layer_dict[layer_name].output
    loss = K.mean(layer_output[:, filter_index, :, :])
    grads = K.gradients(loss, input_img)[0]
    grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)
    iterate = K.function([input_img], [loss, grads])
    step = 1e-0
    input_img_data = np.random.random((1, 3, img_rows, img_cols)) * 20 + 128.
    tm = time.time()
    for i in range(max_steps):
        if (time.time() - tm > 5) and (i % 10 == 0): print(i, '/', max_steps)
        loss_value, grads_value = iterate([input_img_data])
        input_img_data += grads_value * step
        if time.time() - tm > 1:
            plt.text(0.1, 0.1, "Filter viz timeout", color='red')
            break
    img = input_img_data[0]
    img = deprocess_image(img)
    fig = plt.imshow(img)
    fig.axes.get_xaxis().set_visible(False)
    fig.axes.get_yaxis().set_visible(False)
    return layer_output

def viz_losses(losses, scores, accuracies, epoch=0):
    f, (pl1, pl2) = plt.subplots(1, 2, sharey=False, figsize=(12, 5))
    pl1.plot(np.log(losses), label='Train')
    pl1.plot(np.log(scores), label='Test')
    pl2.plot(accuracies, label='Test accuracies')
    pl1.set_title("Log Loss")
    pl2.set_title("Test Accuracy")
    pl1.legend()
    plt.show()

def viz_filters(nbfilters=3):
    for layer_name in sorted(layer_dict.keys()):
        if not hasattr(layer_dict[layer_name], 'nb_filter'): continue
        nfilters = layer_dict[layer_name].nb_filter
        print("Layer", layer_name, "has", nfilters, "filters")
        plt.subplots(1, nbfilters)
        for j in range(nbfilters):
            plt.subplot(1, nbfilters, j + 1)
            viz_filter_max(layer_name, random.randint(0, nfilters-1))
        plt.show()

def test_prediction(im=None, y=None):
    t_img = random.randint(0, len(X_train) - 1)
    if im is None: im, y = X_train[t_img], Y_train[t_img]
    plt.imshow((im.T - im.min()) / (im.max() - im.min()))
    plt.show()
    pred = model.predict_proba(np.expand_dims(im, 0))
    cls = np.argmax(y)
    print("Actual: %s(%d)" % (obj_classes[cls], cls))
    for cls in list(reversed(np.argsort(pred)[0]))[:5]:
        conf = float(pred[0, cls])/pred.sum()
        print("    predicted: %010s(%d), confidence=%0.2f [%-10s]" % (obj_classes[cls], cls, conf, "*" * int(10*conf)))
    return pred

#%% Image data augmentation
from keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
    featurewise_center=False,               # set input mean to 0 over the dataset
    samplewise_center=False,                # set each sample mean to 0
    featurewise_std_normalization=False,    # divide inputs by std of the dataset
    samplewise_std_normalization=False,     # divide each input by its std
    zca_whitening=False,                    # apply ZCA whitening
    rotation_range=0,                       # randomly rotate images in the range (degrees, 0 to 180)
    width_shift_range=0.1,                  # randomly shift images horizontally (fraction of total width)
    height_shift_range=0.1,                 # randomly shift images vertically (fraction of total height)
    horizontal_flip=False,                  # randomly flip images
    vertical_flip=False)                    # randomly flip images
datagen.fit(X_test)

#%% Training code
if loadmodel and os.path.exists("model.h5"): model.load_weights("model.h5")
#from keras.utils import generic_utils
losses, scores, accuracies = [], [], []
for e in range(nb_epoch):
    print('---- Epoch', e, ' ----')
    # Load data subset if needed
    X_train, y_train, obj_classes = load_data(basepath, reference, units, epoch_size, grid_size)
    Y_train = np_utils.to_categorical(y_train, len(obj_classes))
    if normalize:
        X_train = X_train - X_train.mean()
        X_train = X_train / X_train.std()

    print('Sample proportion = %.3f train, %.3f test' %
        (Y_train[:,1].sum() / Y_train[:,1].size, Y_test[:,1].sum() / Y_test[:,1].size))

    print('Training...')
    loss = model.fit_generator(datagen.flow(X_train, Y_train, shuffle=True,
                    batch_size=batch_size),
                    samples_per_epoch=X_train.shape[0],
                    nb_epoch=1,
                    validation_data=(X_test, Y_test))
    if savemodel: model.save_weights("model.h5", overwrite=True)

    losses.append(loss.history['loss']), scores.append(loss.history['val_loss']), accuracies.append(loss.history['val_acc'])
    viz_losses(losses, scores, accuracies, e)
    t_ind = random.randint(0, len(X_train) - 1)
    test_prediction(X_train[t_ind], Y_train[t_ind])
    if e % 20 == 0 and vis_filter:
        try:
            print("Visualizing filters, press CTRL-C to stop...")
            viz_filters()
        except KeyboardInterrupt:
            pass

#%%
"""
# Use datagen.flow() below for test or train images
# prediction_label = True to use predictions as labels
# mode = 'color' as default, 'gray' for grayscale, 'both' for color next to gray
def write_predictions(images, prediction_label=True, mode='color'):
    if not os.path.exists(outpath): os.makedirs(outpath)
    for i, (bx, by) in enumerate(images):
        for im, y in zip(bx, by):
            print(im.shape)
            im = (im.T - im.min()) / (im.max() - im.min())
            if mode == 'color': plt.imshow(im)
            elif mode == 'gray': plt.imshow(im, cmap='gray')
            elif mode == 'both':
                plt.subplots(1, 2)
                plt.subplot(1, 2, 1)
                plt.imshow(im)
                plt.subplot(1, 2, 2)
                plt.imshow(im, cmap='gray')
            pred = model.predict_proba(np.expand_dims(im, 0))
            cls = np.argmax(pred) if label == 'prediction' else np.argmax(y)
            conf = int(100*float(pred[0, cls])/pred.sum())
            clsname = obj_classes[cls]
            clspath = os.path.join(outpath, clsname)
            if not os.path.exists(clspath): os.makedirs(clspath)
            plt.savefig(os.path.join(clspath, "%d-conf-%d.png" % (i, conf)))

write_predictions(datagen.flow(X_test, Y_test), prediction_label=False, mode='color')
"""


import pygame

green = (47, 79, 79)
grey = (128, 128, 128)

def show_speed(speed):
    from main import scrn
    score_font = pygame.font.SysFont("bahnschrift", 25)
    speed_value = score_font.render('speed:' + str(speed), True, grey)
    scrn.blit(speed_value, [8, 30])

def your_snake(snake_block, snake_list):
    '''Snake'''
    from main import scrn
    for x in snake_list:
        pygame.draw.rect(scrn, green, [x[0], x[1], snake_block, snake_block])


#!/usr/bin/env python

import torch
from preprocess.preprocess_cornell import get_id2line,get_data
from torch.autograd import Variable

batch_size=32
voc_size = 15000
max_seq_len = 20
start_word = 0

def sampling_real_data(corpus_name, num_samples):
    sentences, v_list, vocb = get_id2line(corpus_name, voc_size)
    corpus = get_data(sentences, v_list, vocb, max_seq_len)
    num_sentence=corpus.shape[0]
    if num_samples<num_sentence:
        print("Real data Corpus: {:3d}".format(num_samples))
        X = torch.zeros(num_samples, max_seq_len+1)
        randomlist=torch.LongTensor(num_samples).random_(0, num_sentence-1)
        for i in range(num_samples):
            X[i, :] =corpus[randomlist[i],:]
    else:
        print("Real data Corpus: {:3d}".format(num_sentence))
        X = torch.zeros(num_sentence, max_seq_len+1)
        randomlist=torch.LongTensor(num_sentence).random_(0, num_sentence-1)
        for i in range(num_sentence):
            X[i, :] =corpus[randomlist[i],:]

    return X.type(torch.LongTensor), vocb # X is [num_sentence x (1+max_seq_len)] including [START]

def preparing_from_all_real_data(all_real_data, num_sentence,CUDA):
    X = torch.zeros(num_sentence, max_seq_len)
    Y = torch.ones(num_sentence)
    num_all = all_real_data.shape[0]
    randomlist=torch.LongTensor(num_sentence).random_(0, num_all-1)
    for i in range(num_sentence):
        X[i, :] =all_real_data[randomlist[i],1:]
    X=X.type(torch.LongTensor)
    if CUDA:
        X=X.cuda()
    return X, Y  # X is [num_sentence x max_seq_len]

def preparing_new_training_samples_for_D(real_data_samples, num_realdata, G, num_fakedata, CUDA):
    # 1) Generate num_fakedata samples from the fixed G
    # 2) Sampling num_realdata samples from realdataset (already get truncated)

    realX, labels1 = preparing_from_all_real_data(real_data_samples, num_realdata,CUDA)
    fakeX, labels2 = G.preparing_samples_from_fixed_generator(num_fakedata)
    X = torch.cat((realX, fakeX), 0) # cat require both set are .cuda()
    Y = torch.cat((labels1, labels2))  # not LongTensor ??

    # shuffle
    perm = torch.randperm(Y.size()[0])
    Y = Y[perm]
    X = X[perm]

    # Turn to Variables for BP
    X = Variable(X)
    Y = Variable(Y)

    if CUDA:
        X = X.cuda()
        Y = Y.cuda()

    return X, Y

#
# def preparing_new_training_samples_for_G(G, num_fakedata, CUDA):
#     # 1) Generate num_fakedata samples from the fixed G
#     # 2) Sampling num_realdata samples from realdataset (already get truncated)
#
#
#     # X, Y = G.preparing_samples_from_G_for_foolD(num_fakedata)
#     X = G.preparing_samples_from_G_for_foolD(num_fakedata)
#
#     # shuffle
#     perm = torch.randperm(X.size()[0])
#     # Y = Y[perm]
#     X = X[perm]
#
#
#
#     # return X, Y
#     return X


from reportlab.graphics import widgetbase
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate
from reportlab.graphics.shapes import Drawing
story = []
drawing = Drawing(400, 200)
face = widgetbase.Face()
face.skinColor = colors.yellow
face.eyeColor = colors.green
face.mood = 'happy'
drawing.add(face)
story.append(drawing)
pdf = SimpleDocTemplate('face.pdf')
pdf.build(story)


import gspread
from oauth2client.service_account import ServiceAccountCredentials

def setup():
    # use creds to create a client to interact with the Google Drive API
    scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']
    creds = ServiceAccountCredentials.from_json_keyfile_name('client_secret.json', scope)
    client = gspread.authorize(creds)

    #creates an instance of the setupList object that takes care of interactions with the google cloud platform

    ######### stuff that I actually wrote ... ##########

    setupList = [scope,creds,client]

    return setupList
#dont rlly need to worry about this one
def sheetValFunc():
    sheetVal = 3 #the index of the spreadsheet you want to edit
        #another bigly important value-- this index starts at 0
        #0 = clinton
        #1 = centre
        #2 - mifflin
        #3 - Juniata
        #4 - perry
        #5 - rawdata (DO NOT EDIT!)

    return sheetVal
#which sheet are you editing?
def whichColVal():
    print("hey! which column do you want to edit?")
    while True:
        colName = input()
        if colName == "Precinct":
            colVal = 2
            break
        elif colName == "DW":
            colVal = 3
            break
        elif colName == "Committeeman":
            colVal = 4
            break
        elif colName == "Phone":
            colVal = 5
            break
        elif colName == "Email":
            colVal == 6
            break
        elif colName == "Address":
            colVal = 7
            break
        elif colName == "Notes":
            colVal = 8
            break
        elif colName == "Polling Place":
            colVal = 9
            break
        elif colName == "Map":
            colVal = 10
            break
        else:
            print("Not a valid column name! try again")

    #colVal = 9 #the value of the column you want to edit ...this index starts at 1
        #bigly important value
        #1 - empty
        #2 - precinct name
        #3 - DW
        #4 - Committeman name
        #5 - phone#
        #6 = Email
        #7 -- addresses of committeman
        #8 notes
        #9 -- polling places
        #10 - Map

    return colVal
#which column in the sheet are you editing?
def whichFile():
    addrFileName = "juniata_cty_addresses.txt"

    return addrFileName
#which text file has the data you're filling in?

def filler(setupList):

    scope = setupList[0]
    creds = setupList[1]
    client = setupList[2]

    sheet = client.open("Copy of Precincts")
    # -- LIVE! sheet = client.open("Precincts")
    #opens the spreadsheet by its title

    sheetVal = sheetValFunc()
    colVal = whichColVal()

    worksheet = sheet.get_worksheet(sheetVal)
    colValList = worksheet.col_values(colVal) #fetches the values of the chosen column in the chosen spreadsheet
    #print(colValList) -- making sure that the list contains everything (output validation)

    addrFileName = whichFile()
    addrFile = open(addrFileName, "r") #opens the file containing all of the addresses

    table = str.maketrans(dict.fromkeys("\n")) #translation table for removing the newline statements

    addrList = addrFile.readlines() #creates a list of all the values from addresses.txt

    gfList = [] #empty list for just the addresses --"Good Format List"

    for x in range(len(addrList)):
        plcHolder = addrList[x] #holds the value of the current index to be brought to the new list gfList
        plcHolder = plcHolder.translate(table)

        gfList.append(plcHolder)

            #this for loop gets rid of all of the newline statements in the string

    #print(gfList) #output validation oWo

    addrFile.close()
    #row where to begin filling; 8

    editRowVal = 8

    for z in range(len(gfList)):
        newCellVal = gfList[z]
        print(newCellVal)
        worksheet.update_cell((editRowVal + z ), colVal, newCellVal)

        #this for loop updates the values in the spreadsheet, using the list with the new values!

    print("all done -- your spreadsheet has been filled!")

setupList = setup()
filler(setupList)


#!/usr/bin/env python
import rospy
from geometry_msgs.msg import Twist
from turtlesim.msg import Pose
from nav_msgs.msg import Odometry
from math import pow, atan2, sqrt
# from tf.transformations import euler_from_quaternion
from gazebo_msgs.msg import ModelStates
from std_msgs.msg import String
import math
import numpy as np
from tf.transformations import euler_from_quaternion, quaternion_from_euler

class Husky:

    def __init__(self):
        # Creates a node with name 'husky_controller' and make sure it is a
        # unique node (using anonymous=True).
        rospy.init_node('husky_controller', anonymous=True)

        # Publisher which will publish to the topic '/husky_velocity_controller/cmd_vel'.
        self.velocity_publisher = rospy.Publisher('/cmd_vel', Twist, queue_size=10)

        self.goals_X = []
        self.goals_Y = []

        self.sub = rospy.Subscriber('/gazebo/model_states', ModelStates, self.callback)

        # We used Pose() message for the self.robot_pose because the Odometry msg is bigger than needed, so we saved the values of the variables we're interested in from the Odometry msg into this Pose msg
        self.robot_pose = Pose()
        self.human_pose = Pose()

        self.vel_msg = Twist()
        self.rate = rospy.Rate(10)

        self.passing_state = 0
        self.goal_pose = Pose()
        self.goal_k = 0
        self.i = 0

        while not rospy.is_shutdown():
            if(self.passing_state==0):
                self.go_straight()
            else:
                self.p_controller(self.i)

            self.cmd_vel_pub()

    def cmd_vel_pub(self):

        # if(self.passing_state == 0):

        #     # Robot moves forward
        #     self.vel_msg.linear.x = 0.5
        #     self.vel_msg.linear.y = 0
        #     self.vel_msg.linear.z = 0

        #     self.vel_msg.angular.x = 0
        #     self.vel_msg.angular.y = 0
        #     self.vel_msg.angular.z = 0

        # elif(self.passing_state == 1):

        #     if(self.goal_k < 2):

        #         self.goal_pose.x = self.goals_X[self.goal_k]
        #         self.goal_pose.y = self.goals_Y[self.goal_k]
        #         # print("goal pose: %f,%f"%(self.goal_pose.x,self.goal_pose.y))
        #         distance_tolerance = 0.5

        #         if(self.euclidean_distance(self.goal_pose) >= distance_tolerance):

        #                 # Calculating errors
        #                 self.dist_error_X = self.goal_pose.x - self.robot_pose.x
        #                 self.dist_error_Y = self.goal_pose.y - self.robot_pose.y
        #                 self.orientation_error = self.steering_angle(self.goal_pose) - self.robot_pose.theta

        #         else:
        #             self.goal_k += 1
        #             print("next goal" + str(self.goal_k))

        #         self.vel_msg.linear.x = 0.5
        #         self.vel_msg.linear.y = 0
        #         self.vel_msg.linear.z = 0

        #         # Angular velocity in the z-axis.
        #         self.vel_msg.angular.x = 0
        #         self.vel_msg.angular.y = 0
        #         self.vel_msg.angular.z = self.angular_vel(self.goal_pose)
        #         # self.vel_msg.angular.z = 0

        #     elif(self.goal_k == 2):

        #         # Target reached, stop the robot
        #         self.vel_msg.linear.x = 0
        #         self.vel_msg.linear.y = 0
        #         self.vel_msg.linear.z = 0

        #         self.vel_msg.angular.x = 0
        #         self.vel_msg.angular.y = 0
        #         self.vel_msg.angular.z = 0

        #     # Publish vel_msg
        self.velocity_publisher.publish(self.vel_msg)

    def go_straight(self):
        self.vel_msg.linear.x = 1.0
        self.vel_msg.linear.y = 0
        self.vel_msg.linear.z = 0

        self.vel_msg.angular.x = 0
        self.vel_msg.angular.y = 0
        self.vel_msg.angular.z = 0

    def callback(self, data):

        if(len(data.pose) < 3):
            return

        # Extracting positon info from /gazebo/model_states
        self.human_pose.x = data.pose[1].position.x
        self.human_pose.y = data.pose[1].position.y

        # print("Human Pose X: ", self.human_pose.x)
        # print("Human Pose Y: ", self.human_pose.y)

        self.robot_pose.x = data.pose[-1].position.x
        self.robot_pose.y = data.pose[-1].position.y
        #self.robot_pose.theta = data.pose[-1].orientation.w*2

        orientation_q = data.pose[-1].orientation
        orientation_list = [orientation_q.x, orientation_q.y, orientation_q.z, orientation_q.w]
        (roll, pitch, yaw) = euler_from_quaternion (orientation_list)
        self.robot_pose.theta = yaw
        # print("Robot Pose X: ", self.robot_pose.x)
        # print("Robot Pose Y: ", self.robot_pose.y)

        dist = sqrt( pow(self.human_pose.x - self.robot_pose.x, 2) + pow(self.human_pose.y - self.robot_pose.y, 2) )
        # print(dist)

        if ( dist < 10.0 and self.passing_state == 0):

            self.passing_state = 1
            self.goals_X.append(self.human_pose.x-3)
            self.goals_Y.append(self.human_pose.y-3)

            self.goals_X.append(self.human_pose.x-3+25)
            self.goals_Y.append(self.human_pose.y-3)

            print("Update the goal position to: " + str(self.goals_X[0]) + " " + str(self.goals_Y[0]))

        # print("Goals X: ", self.goals_X)
        # print("Goals Y: ", self.goals_Y)

    def euclidean_distance(self, goal_pose):
        """Euclidean distance between current pose and the goal."""
        return sqrt(pow((goal_pose.x - self.robot_pose.x), 2) + pow((goal_pose.y - self.robot_pose.y), 2))

    def linear_vel(self, goal_pose, constant=0.3):
        """See video: https://www.youtube.com/watch?v=Qh15Nol5htM."""
        return constant * self.euclidean_distance(goal_pose)

    def steering_angle(self, goal_pose):
        """See video: https://www.youtube.com/watch?v=Qh15Nol5htM."""
        return atan2(goal_pose.y - self.robot_pose.y, goal_pose.x - self.robot_pose.x)

    def angular_vel(self, goal_pose, constant=1.2):
        """See video: https://www.youtube.com/watch?v=Qh15Nol5htM."""
        return constant * (self.steering_angle(goal_pose) - self.robot_pose.theta)

    def p_controller(self, i):

        # K configuration
        ka = 2.5
        kb = -1.1
        kp = 1

        # Initializing Index
        # i = 0

        # Desired destination
        d_posX = self.goals_X[i]
        d_posY = self.goals_Y[i]
        d_theta = 0

        # Current location
        c_posX = self.robot_pose.x
        c_posY = self.robot_pose.y
        c_theta = self.robot_pose.theta

        # print("c_posX = ", c_posX, "c_posY = ", c_posY, "d_posX = ", d_posX, "d_posY = ", d_posY)

        # Calculating delta X and Y in the robot's global frame
        deltax = d_posX - c_posX
        deltay = d_posY - c_posY
        deltaz = 1

        # Rotation matrix about Z-axis from the goal frame to the global frame
        rotz = np.array([ [math.cos(-d_theta), -math.sin(-d_theta), 0], [math.sin(-d_theta), math.cos(-d_theta), 0], [0, 0, 1] ])

        # Finding the values of delta X, delta Y, and delta Z with respect to the global frame
        deltas = [[deltax], [deltay], [deltaz]]
        [deltaxg,deltayg,deltazg]=np.matmul(rotz, deltas)
        deltas2=[deltaxg,deltayg,deltazg]

        # Defining rho, alpha, and beta
        rho = math.sqrt( (deltaxg)**2 + (deltayg)**2 )
        alpha = (-c_theta + math.atan2( (deltay), (deltax)))
        beta = ( math.atan2( (deltay), (deltax)) - d_theta)

        if(alpha>math.pi):
            alpha-=math.pi*2
        if(alpha<-math.pi):
            alpha+=math.pi*2

        if(beta>math.pi):
            beta-=math.pi*2
        if(beta<-math.pi):
            beta+=math.pi*2

        # print("c_theta = ", round(c_theta,4), "rho=", round(rho,4), "alpha = ", round(alpha,4), "beta= ", round(beta,4))

        # Updating the linear and angular velocities
        c_v = kp * rho
        c_w = ka * alpha + kb * beta

        # Updating current local velocity configurations
        # if (alpha <= math.pi/2 and alpha >= (-(math.pi/2))):

        # # Forward motion control law

        #     if (alpha > math.pi):
        #         alpha = math.pi
        #     if (alpha < -math.pi):
        #         alpha = -math.pi
        #     if (beta > math.pi):
        #         beta = math.pi
        #     if (beta < -math.pi):
        #         beta = -math.pi

        #     # Updating the linear and angular velocities
        #     c_v = kp * rho
        #     c_w = ka * alpha + kb * beta
        #     # print(alpha)
        #     # print(beta)

        #     # Constraining the wheel speeds to less than 16 rad/sec
        #     if (c_v > 24):
        #         c_v = 24

        #     if (c_w > 2):
        #         c_w = 2

        # else:

        #     # Backward motion control law
        #     alpha = (-c_theta + math.atan2(-(d_posY - c_posY), -(d_posX - c_posX)))
        #     beta = -c_theta - alpha

        #     while (alpha > math.pi or alpha < -math.pi):
        #         if (alpha > 0):
        #             alpha = alpha - 2 * math.pi
        #             # print(alpha)
        #         if (alpha < 0):
        #             alpha = alpha + 2 * math.pi
        #             # print(alpha)

        #     if (alpha > math.pi):
        #         alpha = math.pi
        #     if (alpha < -math.pi):
        #         alpha = -math.pi
        #     if (beta > math.pi):
        #         beta = math.pi
        #     if (beta < -math.pi):
        #         beta = -math.pi

        #     # Updating the linear and angular velocities
        #     c_v = -kp * rho
        #     c_w = (ka * alpha + kb * beta)
        #     # print(alpha)
        #     # print(beta)

        #     # Constraining the wheel speeds to less than 16 rad/sec
        #     if (c_v < -24):
        #         c_v = -24

        #     if (c_w < -2):
        #         c_w = -2

        if( c_v > 1.5 ):
            c_v = 1.5

        if( c_w > 1.0 ):
            c_w = 1.0

        self.vel_msg.linear.x = c_v
        self.vel_msg.linear.y = 0
        self.vel_msg.linear.z = 0

        # Angular velocity in the z-axis.
        self.vel_msg.angular.x = 0
        self.vel_msg.angular.y = 0
        self.vel_msg.angular.z = c_w

        # # Calculating robot wheel speeds -- phi_l and phi_r are the robot's wheel speeds
        # r = 16.5 			# robot wheel radius in cm
        # L = 60			# robot chassis radius in cm

        # robot_param_mat = np.array([ [r/2, r/2], [r/(2*L), -r/(2*L)] ])
        # inv_robot_param_mat = np.linalg.inv(robot_param_mat)
        # [phi_r, phi_l] = np.matmul( inv_robot_param_mat, [ [c_v], [c_w]] )		# unit rad/sec

        if abs(c_posX - d_posX) < 1.8 and abs(c_posY - d_posY) < 1.8 and abs(c_theta - d_theta) < 0.4:

            self.i = self.i + 1

            if(self.i < 2):
                self.p_controller(self.i)

            print("final goal reached")

            self.vel_msg.linear.x = 0
            self.vel_msg.linear.y = 0
            self.vel_msg.linear.z = 0

            # Angular velocity in the z-axis.
            self.vel_msg.angular.x = 0
            self.vel_msg.angular.y = 0
            self.vel_msg.angular.z = 0

        #else:
            # print("one goal point reached, continute to next goal point")

        # return False

if __name__ == '__main__':
    try:
        Husky()
        rospy.spin()
    except rospy.ROSInterruptException:
        pass


import os
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw
import unicodedata
import cv2
import csv
import pytesseract
import time

pytesseract.pytesseract.tesseract_cmd = 'C:\\Program Files\\Tesseract-OCR\\tesseract.exe'

class plagcheck:

    def __init__(self, folders_all, files_all):
        self.folders_all = folders_all
        self.files_all = files_all

    def run(self):
        path = "final_txt_files"
        os.chdir(path)
        for file in os.listdir():
            os.remove(file)

        os.chdir('../imgs')
        for file in os.listdir():
            os.remove(file)

        # read the files from the given dataset

        for directory in self.folders_all:

            # store their images in another folder
            for entry in os.scandir(directory):
                if entry.is_file():
                    if entry.name.endswith('.txt'):
                        self.read_text_files(entry.path, entry.name)

        for file in self.files_all:
            self.read_text_files(file, file.split("/")[-1])

        os.chdir('../imgs')
        print('images ', os.listdir())
        # convert it back to text and store it in another folder with the same names as the initial
        for file in os.listdir():
            if file.endswith('.png'):
                self.img_2_text(f'{file}')

        # create an array that stores the names of the files
        arr = os.listdir("../final_txt_files")
        os.chdir('../final_txt_files')
        # create a dictionary to store the list of students with plag % higher than the bench mark
        plag_data = {}

        print(os.curdir.title())
        print(arr)
        time.sleep(2)
        # take the assignments of 2 students at a time and find the plag % for them
        for i in range(len(arr) - 1):
            for j in range(i + 1, len(arr)):
                a = arr[i]
                b = arr[j]
                aa = open(a, encoding="utf8",)
                bb = open(b, encoding="utf8")
                # aa and bb contain the texts of their assignment now
                aa = aa.read()
                bb = bb.read()
                s = self.removeIrrelevantChars(aa)
                ss = self.removeIrrelevantChars(bb)
                x = len(s)
                y = len(s)
                # set the value of sliding window for creating hash table and winnowing based on their lengths
                if min(x, y) <= 2000:
                    d = 5
                else:
                    d = 8
                hashList = self.hashValues(s, d)
                hashList1 = self.hashValues(ss, d)

                z = min(x, y)
                if z > 500:
                    if z > 2000:
                        d = 5
                    else:
                        d = 3
                    fingerprint1 = self.winnowing(hashList, d)
                    fingerprint2 = self.winnowing(hashList1, d)
                    sim = self.printPer(fingerprint1, fingerprint2)
                else:
                    sim = self.printPer_500(hashList, hashList1)
                if sim >= 5:
                    val = str(a.split(".")[0]) + ":" + str(b.split(".")[0])
                    plag_data[val] = sim
        print(plag_data)
        os.chdir('..')

        from CSVfileread import create
        x=create(plag_data)
        x.run()

    def text2png(self, text, fullpath, color="#000", bgcolor="#FFF", fontfullpath=None, fontsize=13, leftpadding=3,
                 rightpadding=3, width=200):
        REPLACEMENT_CHARACTER = u'\uFFFD'
        NEWLINE_REPLACEMENT_STRING = ' ' + REPLACEMENT_CHARACTER + ' '

        font = ImageFont.load_default() if fontfullpath is None else ImageFont.truetype(fontfullpath, fontsize)
        text = text.replace('\n', NEWLINE_REPLACEMENT_STRING)

        lines = []
        line = ""

        for word in text.split(" "):
            if word == REPLACEMENT_CHARACTER:  # give a blank line
                lines.append(line[1:])  # slice the white space in the beginning of the line
                line = ""
                lines.append("")  # the blank line
            elif font.getsize(line + ' ' + word)[0] <= (width - rightpadding - leftpadding):
                line += ' ' + word
            else:  # start a new line
                lines.append(line[1:])
                # slice the white space in the begining of the line
                line = ""

                # TODO: handle too long words at this point
                line += ' ' + word  # for now, assume no word alone can exceed the line width

        if len(line) != 0:
            lines.append(line[1:])  # add the last line

        line_height = font.getsize(text)[1]
        img_height = line_height * (len(lines) + 1)

        img = Image.new("RGBA", (width, img_height), bgcolor)
        draw = ImageDraw.Draw(img)

        y = 0
        for line in lines:
            draw.text((leftpadding, y), line, color, font=font)
            y += line_height

        img.save(fullpath)

    def read_text_files(self, path, name):
        with open(path, encoding='utf8') as f:
            s = f.read()
            generated_img_path = f'../imgs/{name}.png'
            self.text2png(s, generated_img_path, fontfullpath="../font.ttf")

    def img_2_text(self, image_path):
        img = cv2.imread(image_path)
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        y = pytesseract.image_to_string(img)
        x = unicodedata.normalize('NFKD', y).encode('ascii', 'ignore')
        x = x.decode("utf-8")
        f = open(f'../final_txt_files/{image_path.split(".")[0]}.txt', 'w')
        f.write(x)
        f.close()

    def removeIrrelevantChars(self, s):
        # s.replace(" ", "")
        x = ""
        for i in s:
            if ord(i) > 32 and ord(i) < 127:
                x += i
        x = x.lower()
        # print(x)
        return x

    def hashValues(self, s, d):
        code = {"!": 1, "#": 2, "$": 3, "%": 4, "&": 5, "(": 6, ")": 7, "*": 8, "+": 9, ",": 10,
                "-": 11, ".": 12, "/": 13, ":": 14, ";": 15, "<": 16, "=": 17, ">": 18, "?": 19,
                "@": 20, "[": 21, "^": 22, "_": 23, "`": 24, "{": 25, "|": 26, "}": 27, "~": 28,
                "]": 29, "\"": 30, "\'": 31, "a": 32, "b": 33, "c": 34, "d": 35, "e": 36, "f": 37,
                "g": 38, "h": 39, "i": 40, "j": 41,
                "k": 42, "l": 43, "m": 44, "n": 45, "o": 46, "p": 47, "q": 48, "r": 49, "s": 50,
                "t": 51, "u": 52, "v": 53, "w": 54, "x": 55, "y": 56, "z": 57, "0": 58, "1": 59,
                "2": 60, "3": 61, "4": 62, "5": 63, "6": 64, "7": 65, "8": 66, "9": 67, "\\": 68}
        x = 0

        # created a 5-gram
        for i in range(d):
            x += ((109 ** (d - 1 - i)) * code[s[i]])
            # x += pow(100,d-i,100009)
            x = x % 100009
        # print(x)
        lis = []
        lis.append(x)
        # print(x)
        i = 1
        while (i < len(s) - d + 1):
            x = ((x - (109 ** (d - 1)) * code[s[i - 1]]) * 109 + code[s[i + d - 1]])
            x = x % 100009
            lis.append(x)
            i += 1
        # print(lis)
        return lis

    def winnowing(self, lst, d):
        y = len(lst)
        x = 100009
        # window of 3
        winList = []
        for i in range(y - d + 1):
            if x != min(lst[i:i + d]):
                winList.append([min(lst[i:i + d]), i])
                x = min(lst[i:i + d])
        return winList

    def printPer(self, lis1, lis2):
        match = {}
        i = 0
        while (i < len(lis1)):
            # print(match)
            # print(lis1[i][0])
            match[lis1[i][0]] = match.get(lis1[i][0], 0) + 1
            i += 1
        i = 0
        count = 0
        while (i < len(lis2)):
            if lis2[i][0] in match:
                count += 1
                match[lis2[i][0]] -= 1
                if match[lis2[i][0]] == 0:
                    del match[lis2[i][0]]
            i += 1
        # print(len(lis1))
        similarity = (2 * count) / (len(lis1) + len(lis2)) * 100
        # print(similarity)
        return similarity

    def printPer_500(self, lis1, lis2):
        match = {}
        i = 0
        while (i < len(lis1)):
            # print(match)
            # print(lis1[i][0])
            match[lis1[i]] = match.get(lis1[i], 0) + 1
            i += 1
        i = 0
        count = 0
        while (i < len(lis2)):
            if lis2[i] in match:
                count += 1
                match[lis2[i]] -= 1
                if match[lis2[i]] == 0:
                    del match[lis2[i]]
            i += 1
        similarity = (2 * count) / (len(lis1) + len(lis2)) * 100
        return similarity
        # print(similarity)


import datetime
#Determinar signo zodiacal
def Signo(d, m):
    signo = ['acuario','piscis','aries','tauro','geminis','cancer','leo','virgo','libra','escorpio','sagitario','capricornio']
    if((d >= 20) and (m == 1) or (d < 19) and (m == 2)):
        return signo[0]
    elif((d >= 19) and (m == 2) or (d < 21) and (m == 3)):
        return signo[1]
    elif((d >= 21) and (m == 3) or (d < 20) and (m == 4)):
        return signo[2]
    elif((d >= 20) and (m == 4) or (d < 21) and (m == 5)):
        return signo[3]
    elif((d >= 21) and (m == 5) or (d < 21) and (m == 6)):
        return signo[4]
    elif((d >= 21) and (m == 6) or (d < 23) and (m == 7)):
        return signo[5]
    elif((d >= 23) and (m == 7) or (d < 23) and (m == 8)):
        return signo[6]
    elif((d >= 23) and (m == 8) or (d < 23) and (m == 9)):
        return signo[7]
    elif((d >= 23) and (m == 9) or (d < 23) and (m == 10)):
        return signo[8]
    elif((d >= 23) and (m == 10) or (d < 22) and (m == 11)):
        return signo[9]
    elif((d >= 22) and (m == 10) or (d < 22) and (m == 12)):
        return signo[10]
    else:
        return signo[11]
#Solicitar la fecha
print('Por favor, indique su fecha de nacimiento')
dia = int(input('Indique el dia de nacimiento ---> '))
mes = int(input('Indique el numero del mes en que nacio ---> '))
año = int(input('Indique el año en que nacio ---> '))
#Declarar la fecha
date = datetime.datetime(año, mes, dia)
now = datetime.datetime.now()
#Encontrar el tiempo de vida
time = now - date
#Encontrar el tiempo vivido
days = time.days
print("")
print('Dias vividos: ', days)
seconds = time.seconds + ((days*24)*3600)
hours = seconds / 3600
print('Horas vividas:', hours)
print('Segundos vividos: ', seconds)
zodiaco = Signo(dia, mes)
print('Signo zodiacal: ', zodiaco)


"""mentalhealth URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.conf import settings
from mentalapp import views
from django.conf.urls.static import static

urlpatterns = [
    path('index/',views.index),
    path('form/',views.form),

    path('menubar/',views.menubar),
    path('adminmenu/',views.adminmenu),
    path('publicmember/',views.publicmember),
    path('semenu/',views.semenu),
    path('mamenu/',views.mamenu),
    path('esemenu/',views.esemenu),
    path('emamenu/',views.emamenu),
    path('table/',views.table),

    path('login/',views.login),
    path('login1/',views.login1),
    path('adminlogout/',views.adminlogout),
    path('expertlogout/',views.expertlogout),
    path('userlogout/',views.userlogout),

    path('expertreg/',views.expertreg),
    path('expertreg1/',views.expertreg1),
    path('userreg/',views.userreg),
    path('userreg1/',views.userreg1),
    path('viewexpert/',views.viewexpert),
    path('viewwebinar/',views.viewwebinar),
    path('viewreview1/<str:id>',views.viewreview1),
    path('viewevent/',views.viewevent),

    path('admin/',views.admin),
    path('addexpert/',views.addexpert),
    path('addexpert1/',views.addexpert1),
    path('removeexpert/',views.removeexpert),
    path('delexpert/<str:id>',views.delexpert),
    path('updateexpert/',views.updateexpert),
    path('updexpert/<str:id>',views.updexpert),
    path('updateexpert1/<str:id>',views.updateexpert1),
    path('verifyexpert/',views.verifyexpert),
    path('acceptexpert/<str:id>',views.acceptexpert),
    path('rejectexpert/<str:id>',views.rejectexpert),
    path('addquestion/',views.addquestion),
    path('add_question/',views.add_question),
    path('removequestion/',views.removequestion),
    path('remove_question/<str:id>',views.remove_question),
    path('addevent/',views.addevent),
    path('add_event/',views.add_event),
    path('removeevent/',views.removeevent),
    path('remove_event/<str:id>',views.remove_event),
    path('view_testresult/',views.view_testresult),

    path('expert/',views.expert),
    path('add_article/',views.add_article),
    path('addarticle/',views.addarticle),
    path('removearticle/',views.removearticle),
    path('delarticle/<str:id>',views.remove_article),
    path('add_video/',views.add_video),
    path('addvideo/',views.addvideo),
    path('remove_video/',views.remove_video),
    path('removevideo/<str:id>',views.removevideo),

    path('addvideomental/',views.addvideomental),
    path('addvideomental1/',views.addvideomental1),
    path('removevideomental/',views.removevideomental),
    path('removevideomental1/<str:id>',views.removevideomental1),
    path('view_result/',views.view_result),

    path('user/',views.user),
    path('generatequery/',views.generatequery),
    path('addquery/',views.addquery),
    path('viewquery/',views.viewquery),
    path('upload_answer/<str:id>',views.upload_answer),
    path('update_answer/<str:id>',views.update_answer),
    path('view_answer/',views.view_answer),
    path('bookexpert/',views.bookexpert),
    path('bookexpert1/<str:id>',views.bookexpert1),
    path('bookexpert2/',views.bookexpert2),
    path('book_expert/',views.book_expert),
    path('book_expert1/<str:id>',views.book_expert1),
    path('book_expert2/',views.book_expert2),
    path('viewbooking/',views.viewbooking),
    path('view_booking/',views.view_booking),
    path('acceptbooking/<str:id>',views.acceptbooking),
    path('rejectbooking/<str:id>',views.rejectbooking),
    path('accept_booking/<str:id>',views.accept_booking),
    path('reject_booking/<str:id>',views.reject_booking),

    path('givereview/',views.givereview),
    path('give_review/',views.give_review),
    path('addreview/<str:id>',views.addreview),
    path('addreview1/',views.addreview1),
    path('add_review/<str:id>',views.add_review),
    path('add_review1/',views.add_review1),
    path('viewreview/',views.viewreview),
    path('view_review/',views.view_review),

    path('addwebinar/',views.addwebinar),
    path('addwebinar1/',views.addwebinar1),
    path('removewebinar/',views.removewebinar),
    path('removewebinar1/<str:id>',views.removewebinar1),

    path('viewvideos/',views.viewvideos),
    path('viewarticle/',views.viewarticle),
    path('view_videos/',views.view_videos),

    path('attendtest/',views.attendtest),
    path('addresult/<str:id>',views.addresult),
    path('noresult/<str:id>',views.noresult),
    path('finishtest/',views.finishtest),
    path('view_testresult1/',views.view_testresult1),

    path('userse/',views.userse),
    path('userma/',views.userma),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)


import requests
import sys

URL = "https://en.wikipedia.org/w/api.php"
query = sys.argv[1]
PARAMS = {
    'action': 'query',
    'list': 'search',
    'srsearch': query,
    'format': 'json'
}

r = requests.get(url=URL, params=PARAMS)
data = r.json()

print('Top five results for ' + query + ' on Wikipedia')
print('----------------')

for result in data['query']['search'][:5]:
    print (result['title'])


import numpy as np
import copy
import matplotlib.pyplot as plt
from scipy.spatial import KDTree
import os
import webcolors
from osgeo import gdal

#from pycwr.io import read_auto
#from pycwr.draw.RadarPlot import plot_xy,add_rings
from matplotlib.ticker import MaxNLocator
from matplotlib.colors import BoundaryNorm
import matplotlib.colors as colors
import imp
import math

#import pyart
#from pyart.core.transforms import antenna_to_cartesian
#from pyart.core import cartesian_to_geographic
import copy

#constant
R_earth = 6371.393

#获取图例的像素位置区域范围
left_x = 955
upper_y = 665
right_x = 973
lower_y = 858

#右下角图例显示的13个色块所表示颜色的编码，可利用MacOS上一colorSLurp的取色器取色
COLORS = [
    '#AD90F0',
    '#9600B4',
    '#FF00F0',
    '#C00001',
    '#D60100',
    '#FF0200',
    '#FF9000',
    '#E7C000',
    '#FEFF00',
    '#009000',
    '#00D800',
    '#00ECEC',
    '#01A0F6'
]

#把颜色的hex码转换为RGB整数值
colors_arrays = np.array([list(webcolors.hex_to_rgb(c)) for c in COLORS])
#print(colors_arrays)
cm_user=np.array(colors_arrays[::-1])/255.0
icmap=colors.ListedColormap(cm_user,name='my_color')
plt.register_cmap(cmap=icmap)

class Dataset:
    def __init__(self, in_file):
        self.in_file = in_file #Tiff_file
        dataset = gdal.Open(self.in_file)
        self.XSize = dataset.RasterXSize
        self.YSize = dataset.RasterYSize
        self.GeoTransform = dataset.GetGeoTransform()
        self.GetProjection = dataset.GetProjection()
        #self.band1 = dataset.GetRasterBand(1)
    #def get_band(self):
    #    band1 = dataset.GetRasterBand(1)
    #    return band1
    def get_lat_lon(self):
        gtf = self.GeoTransform
        x_range = range(0, self.XSize)
        y_range = range(0, self.YSize)
        x, y = np.meshgrid(x_range, y_range)
        lon = gtf[0] + x*gtf[1] + y*gtf[2]
        lat = gtf[3] + x*gtf[4] + y*gtf[5]
        return lat, lon

def add_ring(ax, azmin,azmax,rings, color="#5B5B5B", linestyle='-', linewidth=0.6, **kwargs):
    #add_ring(ax1, 0,np.pi, [0, 40, 80, 120, 160], linestyle='-', linewidth=1)
    #print("min")
    #print(azmin,azmax)
    theta = np.linspace(azmin, azmax,200)

    for i in rings:
        x0 = i * np.cos(theta)
        y0 = i * np.sin(theta)
        gci = ax.plot(x0, y0, linestyle=linestyle, linewidth=linewidth, color=color, **kwargs) # circle
    for rad in np.arange(azmin, azmax+0.01, np.pi / 6.0):
        gci = ax.plot([0, rings[-1] * np.cos(rad)], \
                [0, rings[-1] * np.sin(rad)], \
                linestyle=linestyle, linewidth=linewidth, color=color, **kwargs) #line

def add_line_air(ax, heading_angle,angle_range,rings, color="#5B5B5B", linestyle='-', linewidth=0.6, **kwargs):
    # the boundary line
    azmin_r = np.deg2rad(heading_angle - 70)
    azmax_r = np.deg2rad(heading_angle + 70 )
    for rad in [azmin_r,azmax_r]:
        print(rad)
        gci = ax.plot([0, rings[-1] * np.cos(rad)], \
            [0, rings[-1] * np.sin(rad)], \
            linestyle=linestyle, linewidth=linewidth+1, color=color, **kwargs) #line

def rotate(x,y,alpha):
    #假设对图片上任意点(x,y)，绕一个坐标点(rx0,ry0)逆时针旋转a角度后的新的坐标设为(x0, y0)，有公式：
    # x0= (x - rx0)*cos(a) - (y - ry0)*sin(a) + rx0 ;
    # y0= (x - rx0)*sin(a) + (y - ry0)*cos(a) + ry0 ;
    alpha = np.deg2rad(alpha)
    x_r = x * np.cos(alpha) - y *np.sin(alpha)
    y_r = x * np.sin(alpha) + y *np.cos(alpha)
    return x_r, y_r

def get_z_from_radar(radar):
    """Input radar object, return z from radar (km, 2D)"""
    azimuth_1D = radar.azimuth['data']
    elevation_1D = radar.elevation['data']
    srange_1D = radar.range['data']
    sr_2d, az_2d = np.meshgrid(srange_1D, azimuth_1D)
    el_2d = np.meshgrid(srange_1D, elevation_1D)[1]
    xx, yy, zz = antenna_to_cartesian(sr_2d/1000.0, az_2d, el_2d)
    return zz + radar.altitude['data']

def plot_list_of_fields(radar, sweep=0, fields=['reflectivity'], vmins=[0],
                        vmaxs=[65], units=['dBZ'], cmaps=['RdYlBu_r'],
                        return_flag=False, xlim=[-150, 150], ylim=[-150, 150],
                        mask_tuple=None):
    num_fields = len(fields)
    if mask_tuple is None:
        mask_tuple = []
        for i in np.arange(num_fields):
            mask_tuple.append(None)
    nrows = (num_fields + 1) // 2
    ncols = (num_fields + 1) % 2 + 1
    fig = plt.figure(figsize=(14.0, float(nrows)*5.5))
    display = pyart.graph.RadarDisplay(radar)
    for index, field in enumerate(fields):
        ax = fig.add_subplot(nrows, 2, index+1)
        display.plot_ppi(field, sweep=sweep, vmin=vmins[index],
                         vmax=vmaxs[index],
                         colorbar_label=units[index], cmap=cmaps[index],
                         mask_tuple=mask_tuple[index])
        display.set_limits(xlim=xlim, ylim=ylim)

    plt.tight_layout()
    if return_flag:
        return display

class Ground2AC():
    def __init__(self, in_file, ac_parameters):
        self.in_file = in_file #Tiff_file
        self.Rmax_Air = ac_parameters['Rmax_Air']
        self.Rmin_Air = ac_parameters['Rmin_Air']
        self.heading_angle =  ac_parameters['heading_angle']
        self.lat =  ac_parameters['ll_center'][0]
        self.lon =  ac_parameters['ll_center'][1]
        self.range_angle = ac_parameters['range_angle']
        self.Bin_length = ac_parameters['Bin_length']

    def plot_range(self):
        ## STEP 1: generate a general view of the airborne radar range
        cmd = "gdal_translate -of GTiff -a_srs \"+proj=lcc +lat_1=30 +lat_2=62 +lat_0=39.0 +lon_0=110 +a=6378137 +b=6378137 +units=m +no_defs\" -a_ullr -3116700.0385205294 1693154.412068708 2017567.3399639379 -2737364.450775645 "
        src = self.in_file
        dst = "dbz.tif"
        os.system(' '.join([cmd, src, dst]))
        #os.system("gdal_translate -of GTiff -a_srs \"+proj=lcc +lat_1=30 +lat_2=62 +lat_0=39.0 +lon_0=110 +a=6378137 +b=6378137 +units=m +no_defs\" -a_ullr -3116700.0385205294 1693154.412068708 2017567.3399639379 -2737364.450775645 Z_RADA_C_BABJ_20220716015400_P_DOR_RDCP_R_ACHN.PNG dbz.tif")
        # 进一步转为等经纬度的GeoTiff文件
        os.system("gdalwarp -t_srs EPSG:4326 dbz.tif dbz_new_ll.tiff")
        ds = gdal.Open("dbz_new_ll.tiff")
        dataset = Dataset("dbz_new_ll.tiff")
        lat, lon = dataset.get_lat_lon() #每个格点的经纬度信息
        rbg_value = np.stack([ds.GetRasterBand(i).ReadAsArray() for i in (1,2,3)]) #每个格点的RGB信息

        min_max = [10, 75]
        vmin, vmax = min_max
        dBZ_levels = np.arange(72.5, 7.5, -5) #由图右下角的colorbar

        dBZ_figure = np.empty(shape=(rbg_value.shape[1],rbg_value.shape[2]))
        for n, colors_array in enumerate(colors_arrays):
            dist = np.sum( (np.transpose(rbg_value,(1,2,0)) - colors_array)**2, axis = 2 )
            dbz_index = np.where( (dist == dist.min()) & (dist.min()< 10) )
            #print(dist.min())
            dBZ_figure[dbz_index] = dBZ_levels[n]-0.1

        dBZ_figure = np.where(dBZ_figure == 0.0, np.nan , dBZ_figure)

        fig = plt.figure(figsize=(12, 6))
        ax = fig.add_subplot(111)

        plt.imshow(np.uint8(np.transpose(rbg_value,(1,2,0))))

        yy, xx = np.where( ( np.abs(lat - self.lat) < 0.04 )  & ( np.abs(lon - self.lon) < 0.04 ) )
        ax.scatter(xx[0], yy[0], s = 1, color = 'red')

        theta = np.linspace(-np.pi/2 + np.deg2rad(self.heading_angle), np.pi/2 + np.deg2rad(self.heading_angle), 200)
        x_list = []
        y_list = []

        for az in theta:
            lllat = self.Rmax_Air *  np.cos(az)/111.0 + self.lat  #y = 80 * sin(az)
            lllon = np.rad2deg(self.Rmax_Air * np.sin(az) /(R_earth * np.cos(np.deg2rad(lllat)))) + self.lon
            y0, x0 = np.where( (np.abs(lat - lllat) < 0.04)  & (np.abs(lon - lllon) < 0.04))
            x_list.append(x0[0])
            y_list.append(y0[0])

        ax.plot(x_list, y_list, color='black', linewidth = 0.8) # circle
        ax.plot([x_list[0],x_list[-1]], [y_list[0],y_list[-1]], color='black', linewidth = 0.8) # line
        plt.savefig('%d range_show.png'%(self.Rmax_Air))

    def plot_ground2ac_white(self):
        radarX, radarY, dbz_ac = self.get_ac()
        print(radarY.min())

        fig = plt.figure(figsize=(12,6))

        #否则会画出很多蓝色
        dbz_ac = np.where(dbz_ac == 0.0, np.nan , dbz_ac)

        min_max = [10, 75]
        vmin, vmax = min_max
        levels = MaxNLocator(nbins=13).tick_values(vmin, vmax)
        ticks = levels

        ax1 = fig.add_subplot(1,1,1)

        #ax1 = fig.add_axes([0.1, 0.3, 0.9, 0.5]) # [left, bottom, width, height]  ,facecolor='black'
        X1,Y1 = rotate(radarX, radarY, self.heading_angle) # rotate should be clockwise --> *-1
        pc = ax1.pcolormesh( X1/1000, Y1/1000, dbz_ac, shading='auto', vmin = vmin, vmax = vmax, cmap=icmap ) #zorder=0,  dbz_ac是跟着转的，因为某个点对应的X1，Y1和dbz_ac是固定的

        rings = np.linspace(0, self.Rmax_Air, 5)
        add_ring(ax1, 0,np.pi, rings, linestyle='-', linewidth=1)
        #ax1.text()
        #plot_xy(ax1, radarX, radarY, dbz_ac) ##画图显示
        ax1.set_title('Transformed airborne radar display with %d km range'%(self.Rmax_Air), fontsize=20)
        ax1.set_xlabel("Distance From Radar In East (km)", fontsize=10)

        plt.colorbar(mappable=pc, ax=ax1, orientation="vertical")
        plt.savefig('%d km_tr.png'%(self.Rmax_Air))

    def plot_ground2ac_black(self):
        radarX, radarY, dbz_ac = self.get_ac()

        min_max = [10, 75]
        vmin, vmax = min_max

        fig = plt.figure(figsize=(12,6), facecolor='black')

        #否则会画出很多蓝色
        dbz_ac = np.where(dbz_ac == 0.0, np.nan , dbz_ac)
        levels = MaxNLocator(nbins=13).tick_values(vmin, vmax)
        ticks = levels

        ax1 = fig.add_subplot(111,facecolor='black')
        #ax1 = fig.add_axes([0.1, 0.3, 0.9, 0.5],facecolor='black') # [left, bottom, width, height]  ,facecolor='black'
        X1,Y1 = rotate(radarX, radarY, self.heading_angle) # rotate should be clockwise --> *-1

        hq_colors = ['Green', 'Yellow', 'Red']
        cmap_hq = colors.ListedColormap(hq_colors)
        rings = np.linspace(0, self.Rmax_Air, 5)
        print(rings)
        add_ring(ax1, 0,np.pi, rings, color='white', linestyle='-', linewidth=1.5)

        pc = ax1.pcolormesh( X1/1000, Y1/1000, dbz_ac, shading='auto', vmin = vmin, vmax = 50, cmap=cmap_hq ) #zorder=0,  dbz_ac是跟着转的，因为某个点对应的X1，Y1和dbz_ac是固定的

        plt.axis('on')
        plt.tick_params(axis='x',colors='white')
        plt.savefig('%d km_tr_black.png'%(self.Rmax_Air))

    def get_ac(self):
        print(self.in_file)
        self.save_dbz(self.in_file)
        cmd = "gdal_translate -of GTiff -a_srs \"+proj=lcc +lat_1=30 +lat_2=62 +lat_0=39.0 +lon_0=110 +a=6378137 +b=6378137 +units=m +no_defs\" -a_ullr -3116700.0385205294 1693154.412068708 2017567.3399639379 -2737364.450775645 "
        src = "dbz.png"
        dst = "dbz.tif"
        #os.system("gdal_translate -of GTiff -a_srs \"+proj=lcc +lat_1=30 +lat_2=62 +lat_0=39.0 +lon_0=110 +a=6378137 +b=6378137 +units=m +no_defs\" -a_ullr -3116700.0385205294 1693154.412068708 2017567.3399639379 -2737364.450775645 dbz.png dbz.tif")
        # 进一步转为等经纬度的GeoTiff文件
        os.system("gdalwarp -t_srs EPSG:4326 dbz.tif dbz_new.tiff")
        ds = gdal.Open("dbz_new.tiff")
        dataset = Dataset("dbz_new.tiff")
        lat, lon = dataset.get_lat_lon() #每个格点的经纬度信息
        rbg_value = np.stack([ds.GetRasterBand(i).ReadAsArray() for i in (1,2,3)]) #每个格点的RGB信息

        dBZ_levels = np.arange(72.5, 7.5, -5) #由图右下角的colorbar

        dBZ_figure = np.empty(shape=(rbg_value.shape[1],rbg_value.shape[2]))
        for n, colors_array in enumerate(colors_arrays):
            dist = np.sum( (np.transpose(rbg_value,(1,2,0)) - colors_array)**2, axis = 2 )
            dbz_index = np.where( (dist == dist.min()) & (dist.min()< 10) )
            #print(dist.min())
            dBZ_figure[dbz_index] = dBZ_levels[n] # -0.1

        dBZ_figure = np.where(dBZ_figure < 10.0, np.nan , dBZ_figure)

        ## Convert to the aircraft-centered grids
        dist_y = (lat - self.lat)*111.0 # unit: km
        dist_x = np.deg2rad((lon - self.lon)) * R_earth * np.cos(np.deg2rad(lat)) # for np.arrays, * is for element-wise product

        R_grid = np.sqrt(dist_y * dist_y + dist_x * dist_x)
        # get the azimuth from 0 to 360 from east
        Az_grid = np.abs(np.arctan(dist_y / dist_x) * 180 / math.pi)
        Az_grid = np.where( (dist_x < 0) & ( dist_y > 0), 180 - Az_grid, Az_grid)
        Az_grid = np.where( (dist_x < 0) & ( dist_y < 0), 180 + Az_grid, Az_grid)
        Az_grid = np.where( (dist_x > 0) & ( dist_y < 0), 360 - Az_grid, Az_grid)
        print(Az_grid.max(),Az_grid.min())

        ngate = int(np.round( (self.Rmax_Air-self.Rmin_Air) * 1000 / self.Bin_length ))
        Azmin = self.heading_angle  - self.range_angle
        Azmax = self.heading_angle  + self.range_angle

        # Calculate the coverage of the radial beam of the current carrier in polar coordinate
        dbz_ac = np.zeros((360, ngate))
        hid_ac = np.zeros((360, ngate))
        longtitude = np.zeros((360, ngate))
        latitude = np.zeros((360, ngate))
        mask_Z = np.zeros((dBZ_figure.shape[0],dBZ_figure.shape[1]))
        radarX = np.zeros((360, ngate))
        radarY = np.zeros((360, ngate))

        for i_az in np.arange(Azmin, Azmax+1): #azimuth comes from east, the direction is counterclockwise
            for i_bin in np.arange(0, ngate):
                i_az_valied = int(self.AngleToValid(i_az))

                x = i_bin * self.Bin_length * np.sin(np.deg2rad(i_az))
                y = i_bin * self.Bin_length * np.cos(np.deg2rad(i_az))
                #radarX.append(x)
                #radarY.append(y)
                radarX[i_az_valied, i_bin]  = x
                radarY[i_az_valied, i_bin]  = y

                lat_grid = y / 1000.0 /111.0 + self.lat
                lon_grid = np.rad2deg(x / 1000.0 /(R_earth * np.cos(np.deg2rad(lat_grid)))) + self.lon
                y_index = np.argmin(np.abs(lat[:, 10] - lat_grid)) #10 is a random number, 因为是等经纬度投影
                x_index = np.argmin(np.abs(lon[10, :] - lon_grid))

                dbz_ac[i_az_valied, i_bin] = dBZ_figure[y_index, x_index]
                longtitude[i_az_valied, i_bin]  = lon_grid
                latitude[i_az_valied, i_bin]    = lat_grid

                mask_Z[y_index, x_index] = 1

        longtitude = np.where(longtitude == 0.0, np.nan, longtitude)
        latitude = np.where(latitude == 0.0, np.nan, latitude)
        return radarX, radarY, dbz_ac

    def save_dbz(self, in_file):
        raw_img_array = plt.imread(in_file)
        #0-255整数形式的RGB数值更为精确和通用，plt.imread读取的颜色为0-1的浮点数，因此转换为int型
        rgb_img_array = (raw_img_array * 255).astype(int)
        #将底图与dbz颜色分离
        #初始化阶段将原始图片数组分别存入两个数组。
        #存dbz的数组为data_img_array
        flaw_img_array = copy.deepcopy(rgb_img_array)
        #存底图的数组为flaw_img_array，由于后期底图的数组主要用于对缝隙的填补，因此使用flaw。
        data_img_array = copy.deepcopy(rgb_img_array)

        # 方法2: 先将图中的dbz剔除掉，得到纯净的底图，然后获取底图带颜色区域的坐标，利用该坐标将底图赋值为白色，从而获取dbz
        # 1. 剔除dbz像素点，提取出底图部分的坐标
        for colors_array in colors_arrays:
            dist = np.sum((rgb_img_array - colors_array) ** 2, axis=2)
            dbz_index = np.where(dist==dist.min())
            flaw_img_array[dbz_index] = np.array([255,255,255])

        flaw_index = np.where(flaw_img_array.sum(axis=2)<255*3) #非白色的坐标位置，即底图的坐标位置

        # 2. 将底图部分赋值为空白
        data_img_array[flaw_index] = np.array([255,255,255])

        data_img_array[upper_y:lower_y+1,left_x:right_x+1] = np.array([255,255,255])

        #以上图片中都有dBZ裂痕，下面进行填补
        # 1. 获取裂痕坐标
        flaw_yx = np.where(flaw_img_array.sum(axis=2)<255*3) #和方法2中的思路一样
        # 2. create a mask
        mask = np.full(raw_img_array.shape[:2], False)
        mask[flaw_yx] = True
        # 3. use scipy.spatial.KDTree to look for the nearest value to fill the cracks
        flaw_xy = flaw_yx[::-1]
        data_xy = np.where(~mask)[::-1]

        data_points = np.array(data_xy).T
        flaw_points = np.array(flaw_xy).T

        data_img_array[mask] = data_img_array[~mask][KDTree(data_points).query(flaw_points)[1]] #返回值是离查询点最近的点的距离和索引
        #save the image array to png
        plt.imsave("dbz.png",np.uint8(data_img_array))

    def AngleToValid(self, angle):
            ans = angle - int(np.floor_divide(angle, 360.0)) * 360
            return ans

if __name__=='__main__':

    infile = 'Z_RADA_C_BABJ_20220716015400_P_DOR_RDCP_R_ACHN.PNG'
    ac_parameters = { "Rmax_Air":240, "Rmin_Air":0, "heading_angle":-8.0365, "ll_center":[29.6682,111.5598], "range_angle":90, "Bin_length":150 }
    gac = Ground2AC(infile, ac_parameters)
    gac.plot_range()
    gac.plot_ground2ac_white()
    gac.plot_ground2ac_black()