import webbrowser, os
import json
import boto3
import io
from io import BytesIO
import sys
from pprint import pprint
from dotenv import load_dotenv
import pandas as pd

load_dotenv()

AWSSecretKey = os.getenv('AWSSecretKey')
AWSAccessKeyId = os.getenv('AWSAccessKeyId')

def get_rows_columns_map(table_result, blocks_map):
    rows = {}
    for relationship in table_result['Relationships']:
        if relationship['Type'] == 'CHILD':
            for child_id in relationship['Ids']:
                cell = blocks_map[child_id]
                if cell['BlockType'] == 'CELL':
                    row_index = cell['RowIndex']
                    col_index = cell['ColumnIndex']
                    if row_index not in rows:
                        # create new row
                        rows[row_index] = {}

                    # get the text value
                    rows[row_index][col_index] = get_text(cell, blocks_map)
    return rows

def get_text(result, blocks_map):
    text = ''
    if 'Relationships' in result:
        for relationship in result['Relationships']:
            if relationship['Type'] == 'CHILD':
                for child_id in relationship['Ids']:
                    word = blocks_map[child_id]
                    if word['BlockType'] == 'WORD':
                        text += word['Text'] + ' '
                    if word['BlockType'] == 'SELECTION_ELEMENT':
                        if word['SelectionStatus'] =='SELECTED':
                            text +=  'X '
    return text

def get_table_csv_results(file_name):

    with open(file_name, 'rb') as file:
        img_test = file.read()
        bytes_test = bytearray(img_test)

    # process using image bytes
    # get the results
    client = boto3.client('textract', aws_access_key_id = AWSAccessKeyId,
            aws_secret_access_key = AWSSecretKey,
            region_name = 'ap-south-1')

    response = client.analyze_document(Document={'Bytes': bytes_test}, FeatureTypes=['TABLES'])

    # Get the text blocks
    blocks=response['Blocks']

    blocks_map = {}
    table_blocks = []
    for block in blocks:
        blocks_map[block['Id']] = block
        if block['BlockType'] == "TABLE":
            table_blocks.append(block)

    if len(table_blocks) <= 0:
        return "<b> NO Table FOUND </b>"

    csv = ''
    for index, table in enumerate(table_blocks):
        csv = generate_table_csv(table, blocks_map, index +1)

    return csv

def generate_table_csv(table_result, blocks_map, table_index):
    rows = get_rows_columns_map(table_result, blocks_map)

    columns = []
    entity = []
    obs = []
    unit = []
    interval = []

    for row_index, cols in rows.items():
        if row_index == 1:
            for col_index, text in cols.items():
                columns.append(text.strip())
        else:
            entity.append(cols[1].strip())
            if cols[2] == '':
                obs.append(-1)
            else:
                cols[2] = cols[2].replace(',', '')
                obs.append(float(cols[2]))
            unit.append(cols[3].strip())
            if cols[4] == '':
                interval.append(-1)
            else:
                interval.append(cols[4].strip())

    data = {
        columns[0] : entity,
        columns[1] : obs,
        columns[2] : unit,
        columns[3] : interval
    }

    df = pd.DataFrame(data)
    return df

def analysis(df):
    anomalies = {}
    columns = df.columns
    for i in range(len(df)):
        parameter = df.loc[i, columns[0]]
        observed = df.loc[i, columns[1]]
        limits = df.loc[i, columns[3]]
        vals = []
        if int(observed) == -1 and int(limits) == -1:
            pass
        else:
            limits = limits.split("-")
            max_limit = float(limits[1])
            min_limit = float(limits[0])
            adj_max = float(max_limit/0.9)
            adj_min = float(((min_limit/adj_max) - 0.1)*adj_max)
            if float(observed) < adj_min:
                vals.append("low")
                vals.append(1)
            elif float(observed) > adj_max:
                vals.append("high")
                vals.append(1)
            elif float(observed) < adj_max and float(observed) > max_limit:
                vals.append("high")
                vals.append(0)
            elif float(observed) > adj_min and float(observed) < min_limit:
                vals.append("low")
                vals.append(0)
        if vals != []:
            anomalies[parameter] = vals
    return anomalies

# def getPriorityValue(word, priority_list):
#   for key in priority_list:
#     if word == key:
#       return priority_list.get(key).get('priority')
#   for i in priority_list.keys():
#     if type(priority_list.get(i)) == list:
#       sub_list = priority_list.get(i)[0]
#       for key in sub_list:
#         if word == key:
#           return sub_list.get(key).get('priority')
#   return 6

# def getPriority(output, priority_list):
#   key_dict = list(output.keys())
#   final_list = []
#   final_priority = 5
#   for i in key_dict:
#     val = getPriorityValue(i, priority_list)
#     print(final_list)
#     if val < final_priority:
#       final_priority = val
#       final_list.clear()
#       final_list.append(i)
#     elif val == final_priority:
#       final_list.append(i)
#   return final_list

# def getAnalysis(result_list, output, report_list):
#   for i in result_list:
#     rep_list = report_list.get(i)
#     if rep_list == None:
#       for j in report_list.keys():
#         if type(report_list.get(j)) == list:
#           sub_list = report_list.get(j)[0]
#           for key in sub_list:
#             if i == key:
#               rep_list = sub_list.get(key)
#     print(rep_list)
#     output_value = output.get(i)
#     output_list = rep_list.get(output_value[0])
#     output_remedy = rep_list.get("remedy_" + output_value[0])
#     if output_value[1] == 1:
#       print("you need to visit a " + output_list[1])
#     if output_list[0]:
#       print(output_list[0])
#     print("Remedy: ", output_remedy)

def getAnalysis(output, report_list, priority_list):
  result_list = list(output.keys())
  final_dict = {}
  high_priority_dict = {}
  high_pri = 6
  for i in result_list:
    rep_list = report_list.get(i)
    if rep_list != None:
      priority = priority_list.get(i)
      rep_list['priority'] = priority['priority']
      final_dict[i] = rep_list
      if priority['priority'] < high_pri:
        high_pri = priority['priority']
        high_priority_dict.clear()
        high_priority_dict[i] = rep_list
      elif priority['priority'] == high_pri:
        high_priority_dict[i] = rep_list
  print("Final list of all: ", final_dict)
  print("Highest priority: ", high_priority_dict)

def main(file_name):
    table_csv = get_table_csv_results(file_name)
    anomalies = analysis(table_csv)
    print(anomalies)
    #Sample Output:
    output = {'Eosinophils ': ['high', 1], 'MPV (Mean Platelet Volume) ': ['high', 0]}

    f = open('../../Report Analysis/analysis.json')
    report_list = json.load(f)
    print(report_list)
    f.close()
    g = open('../../Report Analysis/priority.json')
    priority_list = json.load(g)
    print(priority_list)
    g.close()

    # result_list = getPriority(output, priority_list)
    # getAnalysis(result_list, output, report_list)

    getAnalysis(output, report_list, priority_list)

if __name__ == "__main__":
    file_name = sys.argv[1]
    main(file_name)


# -*- coding: utf-8 -*-
"""
Created on Sun Dec 13 17:05:23 2020

@author: Ruo-Yah Lai
"""

import matplotlib.pyplot as plt
import numpy as np
import csv
import ast

def spikePlots(turns, unit, subfield, filename, df, title=""):
    """
    turns: from alleyTransitions
    filename: the file with which locations a field is in
    df: path to the files with which locations a field is in
    """
    with open(df+filename, "r") as csv_file:
        data_iter = csv.reader(csv_file)
        data = [data for data in data_iter]
    fieldLoc = ast.literal_eval(data[subfield+1][1])
    turns2 = np.empty((0,5)) #turns in the field
    for turn in turns:
        allLoc = fieldLoc + list(turn[5:8])
        if len(set(allLoc)) < len(allLoc):
            #exclude back around turns that are not in the field
            if len(set(turn[5:8])) == 2 and len(set(allLoc)) == len(allLoc)-1:
                continue
            turns2 = np.vstack((turns2, turn[:5].astype(float))) #allo before turn, ego, allo after turn, ts of exit, ts of entry

    fig, axs = plt.subplots(10,10,figsize=(20,20))
    axs = axs.flatten()
    for i in range(100):
        p = unit.position[np.logical_and(turns2[i,3]-0.5e6 < unit.position[:,0],
                                         unit.position[:,0] < turns2[i,4]+0.5e6)]
        s = unit.spikes[np.logical_and(turns2[i,3]-0.5e6 < unit.spikes[:,0],
                                         unit.spikes[:,0] < turns2[i,4]+0.5e6)]
        axs[i].plot(p[:,1], p[:,2], color=(0.5,0.5,0.5))
        axs[i].scatter(s[:,1], s[:,2], color="red", s=4, zorder=3)
        axs[i].scatter(p[0,1], p[0,2], c="green", s=4, zorder=4)
        axs[i].scatter(p[-1,1], p[-1,2], c="blue", s=4, zorder=4)
    fig.tight_layout()
    fig.suptitle(f"{title}\nGreen = beginning   Blue = end", y=1.02)


import os
import bs4
from nltk.corpus.reader.api import CorpusReader
from nltk.corpus.reader.api import CategorizedCorpusReader
import nltk
import time
from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd
from sklearn.feature_extraction import text
from nltk import sent_tokenize
from nltk import wordpunct_tokenize
from nltk.stem import WordNetLemmatizer
from sklearn.decomposition import PCA
from numpy.linalg import svd
import numpy as np
from functools import reduce
import matplotlib.pyplot as plt
#1시간정도걸림

#nltk.download('wordnet')
#nltk.download('punkt')
#nltk.download('averaged_perceptron_tagger')
#nltk.download('omw-1.4')

CAT_PATTERN = r'([a-su-z]+)/.*'
DOC_PATTERN = r'(?!\.)[a-z_\s]+/[0-9]+\.html'
TAGS = []
title_TAGS = ['h1']
abstract_TAGS = ['blockquote']

class HTMLCorpusReader(CategorizedCorpusReader, CorpusReader):
    """
    A corpus reader for raw HTML documents to enable preprocessing.
    """

    def __init__(self, root, fileids=DOC_PATTERN, encoding='utf8',
                 tags=TAGS, **kwargs):
        """
        Initialize the corpus reader.  Categorization arguments
        (``cat_pattern``, ``cat_map``, and ``cat_file``) are passed to
        the ``CategorizedCorpusReader`` constructor.  The remaining
        arguments are passed to the ``CorpusReader`` constructor.
        """
        # Add the default category pattern if not passed into the class.
        if not any(key.startswith('cat_') for key in kwargs.keys()):
            kwargs['cat_pattern'] = CAT_PATTERN

        # Initialize the NLTK corpus reader objects
        CategorizedCorpusReader.__init__(self, kwargs)
        CorpusReader.__init__(self, root, fileids, encoding)

        # Save the tags that we specifically want to extract.
        self.tags = tags

    def resolve(self, fileids, categories):
        """
        Returns a list of fileids or categories depending on what is passed
        to each internal corpus reader function. Implemented similarly to
        the NLTK ``CategorizedPlaintextCorpusReader``.
        """
        if fileids is not None and categories is not None:
            raise ValueError("Specify fileids or categories, not both")

        if categories is not None:
            return self.fileids(categories)
        return fileids

    def docs(self, fileids=None, categories=None):
        """
        Returns the complete text of an HTML document, closing the document
        after we are done reading it and yielding it in a memory safe fashion.
        """
        # Resolve the fileids and the categories
        fileids = self.resolve(fileids, categories)

        # Create a generator, loading one document into memory at a time.
        for path in self.abspaths(fileids):
            with open(path, 'r', encoding='UTF-8') as f:
                yield f.read()

    def sizes(self, fileids=None, categories=None):
        """
        Returns a list of tuples, the fileid and size on disk of the file.
        This function is used to detect oddly large files in the corpus.
        """
        # Resolve the fileids and the categories
        fileids = self.resolve(fileids, categories)

        # Create a generator, getting every path and computing filesize
        for path in self.abspaths(fileids):
            yield os.path.getsize(path)

def describe(paragraphs, fileids, categories):
    started = time.time()

    counts = nltk.FreqDist()
    tokens = nltk.FreqDist()

    for para in paragraphs:
        counts['paras'] += 1

        for sent in nltk.sent_tokenize(para):
            counts['sents'] += 1

            for word in nltk.wordpunct_tokenize(sent):
                counts['words'] += 1
                tokens[word] += 1

    n_fileids = len(fileids)
    n_topics = len(categories)

    return {
        'files':  n_fileids,
        'topics': n_topics,
        'paragraphs':  counts['paras'],
        'sentences':  counts['sents'],
        'words':  counts['words'],
        'vocabulary size':  len(tokens),
        'lexical diversity': float(counts['words']) / float(len(tokens)),
        'paragraphs per document':  float(counts['paras']) / float(n_fileids),
        'sentences per paragraph':  float(counts['sents']) / float(counts['paras']),
        'secs':   time.time() - started,
    }

def paras(htmls, TAGS):
    for html in htmls:
        soup = bs4.BeautifulSoup(html, 'lxml')
        for element in soup.find_all(TAGS):
            yield element.text
        soup.decompose()

def sents(paragraph):
    for sentence in sent_tokenize(paragraph):
        yield sentence

def words(paragraph):
    for sentence in sents(paragraph):
        for word in wordpunct_tokenize(sentence):
            yield word

def sklearn_tfidf_vectorize(corpus):
    my_stop_words = text.ENGLISH_STOP_WORDS.union(['abstract', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
                                                   'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                                                   'w', 'x', 'y', 'z', ''])
    tfidf = TfidfVectorizer(token_pattern='[a-zA-Z]*', stop_words=my_stop_words, min_df=5, sublinear_tf=True, max_df=0.85)
    res = tfidf.fit_transform(corpus)
    print(tfidf.get_feature_names()[:100])
    return res

def mindf005_sklearn_tfidf_vectorize(corpus):
    my_stop_words = text.ENGLISH_STOP_WORDS.union(['abstract', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
                                                   'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                                                   'w', 'x', 'y', 'z', ''])
    tfidf = TfidfVectorizer(token_pattern='[a-zA-Z]*', stop_words=my_stop_words, min_df=0.05, sublinear_tf=True, max_df=0.85)
    res = tfidf.fit_transform(corpus)
    print(tfidf.get_feature_names()[:100])
    return res

def mindf001_sklearn_tfidf_vectorize(corpus):
    my_stop_words = text.ENGLISH_STOP_WORDS.union(['abstract', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
                                                   'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                                                   'w', 'x', 'y', 'z', ''])
    tfidf = TfidfVectorizer(token_pattern='[a-zA-Z]*', stop_words=my_stop_words, min_df=0.01, sublinear_tf=True, max_df=0.85)
    res = tfidf.fit_transform(corpus)
    print(tfidf.get_feature_names()[:100])
    return res

def mindf0001_sklearn_tfidf_vectorize(corpus):
    my_stop_words = text.ENGLISH_STOP_WORDS.union(['abstract', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
                                                   'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                                                   'w', 'x', 'y', 'z', ''])
    tfidf = TfidfVectorizer(token_pattern='[a-zA-Z]*', stop_words=my_stop_words, min_df=0.001, sublinear_tf=True, max_df=0.85)
    res = tfidf.fit_transform(corpus)
    print(tfidf.get_feature_names()[:100])
    return res

title_corpus = HTMLCorpusReader('', CAT_PATTERN, DOC_PATTERN, tags=title_TAGS)
title_fileids = title_corpus.fileids()
title_documents = title_corpus.docs(categories=title_corpus.categories())
title_htmls = list(title_documents)

abstract_corpus = HTMLCorpusReader('', CAT_PATTERN, DOC_PATTERN, abstract_TAGS)
abstract_fileids = abstract_corpus.fileids()
abstract_documents = abstract_corpus.docs(categories=abstract_corpus.categories())
abstract_htmls = list(abstract_documents)

title_categories = title_corpus.categories()
abstract_categories = abstract_corpus.categories()

title_paragraphs = list(paras(title_htmls, title_TAGS))
temp_title_paragraphs = []
for para in title_paragraphs:
    if "Title:" in para: # and len(para)>30
        temp_title_paragraphs.append(para.strip('Title:\n'))
title_paragraphs = temp_title_paragraphs
print("title_paragraphs len: ", len(title_paragraphs))
print("descreibe title_paragraphs", describe(title_paragraphs, title_fileids, title_categories))

abstract_paragraphs = list(paras(abstract_htmls, abstract_TAGS))
print("abstract_paragraphs len: ", len(abstract_paragraphs))
print("descreibe abstract_paragraphs", describe(abstract_paragraphs, abstract_fileids, abstract_categories))

papers_list = []
for key, value in zip(title_paragraphs, abstract_paragraphs):
    temp_dict = dict()
    temp_dict['title'] = key
    temp_dict['abstract'] = value
    papers_list.append(temp_dict)

print("papers_list[:5] : ", papers_list[:5])

print("title paragraphs[:5] : ", title_paragraphs[:5])

sparse_title_tf_idf = sklearn_tfidf_vectorize(title_paragraphs)
print(sparse_title_tf_idf)
print("type of sparse_title_tf_idf : ", type(sparse_title_tf_idf))

title_tf_idf = sparse_title_tf_idf.todense()
print(title_tf_idf)
print("type of title_tf_idf : ", type(title_tf_idf))

title_tf_idf_df = pd.DataFrame(title_tf_idf)
print(title_tf_idf_df.head())
print("title_tf_idf_df.shape : ", title_tf_idf_df.shape)

df = pd.DataFrame(papers_list, columns={'title', 'abstract'})
print(df.head())
print("df.shape : ", df.shape)
print("abstract_paragraphs: ", abstract_paragraphs[:5])

abstract_words = []
for p in abstract_paragraphs:
    abstract_words.append(list(words(p)))
print(abstract_words[0])
lemma_abstract_words = []
n=WordNetLemmatizer()
for words in abstract_words:
    lemma_abstract_words.append([n.lemmatize(w) for w in words])
print(lemma_abstract_words[0])
print(len(lemma_abstract_words))

lemma_abstract_paragraphs = []
for l in lemma_abstract_words:
    lemma_abstract_paragraphs.append(" ".join(l))
print(lemma_abstract_paragraphs[0])
print(len(lemma_abstract_paragraphs))

lemma_sparse_tf_idf = sklearn_tfidf_vectorize(lemma_abstract_paragraphs)
print(lemma_sparse_tf_idf)
print("type of lemma_sparse_tf_idf : ", type(lemma_sparse_tf_idf))

lemma_tf_idf = lemma_sparse_tf_idf.todense()
print(lemma_tf_idf)
print("type of lemma_tf_idf : ", type(lemma_tf_idf))

lemma_tf_idf_df = pd.DataFrame(lemma_tf_idf)
print(lemma_tf_idf_df.head())
print("lemma_tf_idf_df.shape : ", lemma_tf_idf_df.shape)

sparse_tf_idf = sklearn_tfidf_vectorize(abstract_paragraphs)
print(sparse_tf_idf)
print("type of sparse_tf_idf : ", type(sparse_tf_idf))

tf_idf = sparse_tf_idf.todense()
print(tf_idf)
print("type of tf_idf : ", type(tf_idf))

tf_idf_df = pd.DataFrame(tf_idf)
print(tf_idf_df.head())
print("tf_idf_df.shape : ", tf_idf_df.shape)

mindf005_sparse_tf_idf = mindf005_sklearn_tfidf_vectorize(abstract_paragraphs)
print(mindf005_sparse_tf_idf)
print("type of mindf005_sparse_tf_idf : ", type(mindf005_sparse_tf_idf))

mindf005_tf_idf = mindf005_sparse_tf_idf.todense()
print(mindf005_tf_idf)
print("type of mindf005_tf_idf : ", type(mindf005_tf_idf))

mindf005_tf_idf_df = pd.DataFrame(mindf005_tf_idf)
print(mindf005_tf_idf_df.head())
print("mindf005_tf_idf_df.shape : ", mindf005_tf_idf_df.shape)

mindf001_sparse_tf_idf = mindf001_sklearn_tfidf_vectorize(abstract_paragraphs)
print(mindf001_sparse_tf_idf)
print("type of mindf001_sparse_tf_idf : ", type(mindf001_sparse_tf_idf))

mindf001_tf_idf = mindf001_sparse_tf_idf.todense()
print(mindf001_tf_idf)
print("type of mindf001_tf_idf : ", type(mindf001_tf_idf))

mindf001_tf_idf_df = pd.DataFrame(mindf001_tf_idf)
print(mindf001_tf_idf_df.head())
print("mindf001_tf_idf_df.shape : ", mindf001_tf_idf_df.shape)

mindf0001_sparse_tf_idf = mindf0001_sklearn_tfidf_vectorize(abstract_paragraphs)
print(mindf0001_sparse_tf_idf)
print("type of mindf0001_sparse_tf_idf : ", type(mindf0001_sparse_tf_idf))

mindf0001_tf_idf = mindf0001_sparse_tf_idf.todense()
print(mindf0001_tf_idf)
print("type of mindf0001_tf_idf : ", type(mindf0001_tf_idf))

mindf0001_tf_idf_df = pd.DataFrame(mindf0001_tf_idf)
print(mindf0001_tf_idf_df.head())
print("mindf0001_tf_idf_df.shape : ", mindf0001_tf_idf_df.shape)

mindf005_lemma_sparse_tf_idf = mindf005_sklearn_tfidf_vectorize(lemma_abstract_paragraphs)
print(mindf005_lemma_sparse_tf_idf)
print("type of mindf005_lemma_sparse_tf_idf : ", type(mindf005_lemma_sparse_tf_idf))

mindf005_lemma_tf_idf = mindf005_lemma_sparse_tf_idf.todense()
print(mindf005_lemma_tf_idf)
print("type of mindf005_lemma_tf_idf : ", type(mindf005_lemma_tf_idf))

mindf005_lemma_tf_idf_df = pd.DataFrame(mindf005_lemma_tf_idf)
print(mindf005_lemma_tf_idf_df.head())
print("mindf005_lemma_tf_idf_df.shape : ", mindf005_lemma_tf_idf_df.shape)

mindf001_lemma_sparse_tf_idf = mindf001_sklearn_tfidf_vectorize(lemma_abstract_paragraphs)
print(mindf001_lemma_sparse_tf_idf)
print("type of mindf001_lemma_sparse_tf_idf : ", type(mindf001_lemma_sparse_tf_idf))

mindf001_lemma_tf_idf = mindf001_lemma_sparse_tf_idf.todense()
print(mindf001_lemma_tf_idf)
print("type of mindf001_lemma_tf_idf : ", type(mindf001_lemma_tf_idf))

mindf001_lemma_tf_idf_df = pd.DataFrame(mindf001_lemma_tf_idf)
print(mindf001_lemma_tf_idf_df.head())
print("mindf001_lemma_tf_idf_df.shape : ", mindf001_lemma_tf_idf_df.shape)

mindf0001_lemma_sparse_tf_idf = mindf0001_sklearn_tfidf_vectorize(lemma_abstract_paragraphs)
print(mindf0001_lemma_sparse_tf_idf)
print("type of mindf0001_lemma_sparse_tf_idf : ", type(mindf0001_lemma_sparse_tf_idf))

mindf0001_lemma_tf_idf = mindf0001_lemma_sparse_tf_idf.todense()
print(mindf0001_lemma_tf_idf)
print("type of mindf0001_lemma_tf_idf : ", type(mindf0001_lemma_tf_idf))

mindf0001_lemma_tf_idf_df = pd.DataFrame(mindf0001_lemma_tf_idf)
print(mindf0001_lemma_tf_idf_df.head())
print("mindf0001_lemma_tf_idf_df.shape : ", mindf0001_lemma_tf_idf_df.shape)

title_tf_idf_df.to_csv('title_tf_idf_df.csv')
df.to_csv('df.csv')
tf_idf_df.to_csv('tf_idf_df.csv')
mindf005_tf_idf_df.to_csv('mindf005_tf_idf_df.csv')
mindf001_tf_idf_df.to_csv('mindf001_tf_idf_df.csv')
mindf0001_tf_idf_df.to_csv('mindf0001_tf_idf_df.csv')
lemma_tf_idf_df.to_csv('lemma_tf_idf_df.csv')
mindf005_lemma_tf_idf_df.to_csv('mindf005_lemma_tf_idf_df.csv')
mindf001_lemma_tf_idf_df.to_csv('mindf001_lemma_tf_idf_df.csv')
mindf0001_lemma_tf_idf_df.to_csv('mindf0001_lemma_tf_idf_df.csv')
print("csv saving done")


from django.contrib import admin
from .models import Quiz, Category, Question, Answer, UserAnswers

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    """
    Модель категорий для вывода в админ панели.
    """

    list_display = ('id', 'category_name', 'created_at')
    list_display_links = ('id', 'category_name')
    search_fields = ('category_name',)
    list_filter = ('created_at',)

@admin.register(Quiz)
class QuizAdmin(admin.ModelAdmin):
    """
    Модель опросов для вывода в админ панели.
    """

    list_display = ('id', 'quiz_name', 'category', 'created_at')
    list_display_links = ('id', 'quiz_name')
    search_fields = ('quiz_name',)
    list_filter = ('created_at', 'category')

class AnswerInline(admin.StackedInline):
    model = Answer
    min_num = 4
    extra = 0

@admin.register(Question)
class QuestionAdmin(admin.ModelAdmin):
    """
    Модель вопросов для вывода в админ панели.
    """

    inlines = [AnswerInline]
    list_display = ('id', 'question', 'quiz', 'created_at')
    list_display_links = ('id', 'question')
    search_fields = ('quiz',)
    list_filter = ('quiz', 'created_at')

@admin.register(Answer)
class AnswerAdmin(admin.ModelAdmin):
    """
    Модель ответов для вывода в админ панели.
    """

    list_display = ('id', 'answer', 'is_correct', 'question', 'created_at')
    list_display_links = ('id', 'answer')
    search_fields = ('answer', 'question')
    list_filter = ('is_correct', 'question', 'created_at')

@admin.register(UserAnswers)
class UserAnswersAdmin(admin.ModelAdmin):
    """
    Модель ответов пользователей для админ панели.
    """

    list_display = ('user', 'answer')
    list_filter = ('answer',)
    search_fields = ('answer',)


"""
    Objet Contact représentant un contact de l'Annuaire

    Author: Tristan Colombo <tristan@gnulinuxmag.com>
                            (@TristanColombo)

    Date: 17-12-2015

    Last modification: 17-12-2015

    Licence: GNU GPL v3 (voir fichier gpl_v3.txt joint)
"""

import sqlite3
import pystache
import os

class Contact:

    base = None
    cursor = None
    template = None

    def __init__(self, name, db_args):
        name = name.split(' ')

        if len(name) != 2:
            print('Vous devez saisir un prénom suivi du nom')
            print('Syntaxe: Prénom Nom')
            exit(1)

        if Contact.base is None:
            Contact.base = db_args[0]
        if Contact.cursor is None:
            Contact.cursor = db_args[1]

        if Contact.template is None:
            try:
                with open('doc.tex', 'r') as fic:
                    Contact.template = fic.read()
            except:
                print('Accès impossible au gabarit')
                exit(3)

        self.forename = Contact.capitalizeName(name[0])
        self.name = Contact.capitalizeName(name[1])
        self.mail = self.searchMail()

    @staticmethod
    def capitalizeName(name):
        capitalized = ''
        pred = ''
        for letter in name:
            if pred in ('', ' ', '-'):
                if letter != ' ':
                    capitalized += letter.upper()
            else:
                capitalized += letter
            pred = letter

        return capitalized

    def isInDB(self):
        result = Contact.cursor.execute("""select name from Contact
                               where forename = ?
                               and name = ?""", (self.forename,
                                                 self.name))
        result = result.fetchone()
        return result is not None

    def addInDB(self):
        try:
            Contact.cursor.execute("""insert into Contact
                                   values(NULL, ?, ?, ?)""",
                                   (self.name, self.forename, self.mail))
            Contact.base.commit()
        except sqlite3.OperationalError:
            print('Erreur d\'écriture dans la base')
            exit(2)

    def searchMail(self):
        mail = Contact.cursor.execute("""select mail from Contact
                               where forename = ?
                               and name = ?""", (self.forename,
                                                 self.name))
        mail = mail.fetchone()
        if mail is None:
            return None
        else:
            return mail[0]

    def getMail(self):
        if self.__mail is None:
            return self.searchMail()
        else:
            return self.__mail
    def setMail(self, mail):
        if mail is None:
            self.__mail = None
        else:
            self.__mail = mail.lower()
            if self.isInDB():
                try:
                    Contact.cursor.execute("""update Contact
                                   set mail = ?
                                   where name = ?
                                   and forename = ?""",
                                   (self.mail, self.name, self.forename))
                    Contact.base.commit()
                except sqlite3.OperationalError:
                    print('Erreur d\'écriture dans la base')
                    exit(2)
            else:
                self.addInDB()
    mail = property(getMail, setMail)

    def getName(self):
        return self.__name
    def setName(self, name):
        self.__name = name
    name = property(getName, setName)

    def getForename(self):
        return self.__forename
    def setForename(self, forename):
        self.__forename = forename
    forename = property(getForename, setForename)

    def generateDoc(self, sun=False):
        try:
            with open('doc_contact.tex', 'w') as fic:
                fic.write(pystache.render(Contact.template,
                              {'name': self.name,
                               'forename': self.forename,
                               'sun': sun}))

            # Génération du PDF
            os.system('pdflatex doc_contact.tex 1>/dev/null')
        except:
            print('Erreur lor de la génération du PDF')
            exit(4)


import cv2
import numpy as np
import matplotlib.pyplot as plt

img1 = cv2.imread('shanghai-11.png')
img2 = cv2.imread('shanghai-12.png')
img3 = cv2.imread('shanghai-13.png')

plt.figure(1)
plt.subplot(131), plt.imshow(img1, cmap='gray'), plt.title("Image 1")
plt.subplot(132), plt.imshow(img2, cmap='gray'), plt.title("Image 2")
plt.subplot(133), plt.imshow(img3, cmap='gray'), plt.title("Image 3")
plt.show()

orbObj = cv2.ORB_create()  # Create ORB Object
kp1, descriptors1 = orbObj.detectAndCompute(img1, None)  # Computing descriptors and keypoints
kp2, descriptors2 = orbObj.detectAndCompute(img2, None)
kp3, descriptors3 = orbObj.detectAndCompute(img3, None)

matcher = cv2.DescriptorMatcher_create(cv2.DESCRIPTOR_MATCHER_BRUTEFORCE_HAMMING)  # Creating Matcher Object
GOOD_MATCH_PERCENT = 0.15
MAX_MATCHES = 25

# Image 1 - Image 2 Matcher
matches1 = matcher.match(descriptors1, descriptors2, None)
matches1 = sorted(matches1, key=lambda x: x.distance, reverse=False)
good_matches1 = int(len(matches1) * GOOD_MATCH_PERCENT)
matches1 = matches1[:good_matches1]  # Remove weak matches

# Image 1 - Image 3 Matcher
matches2 = matcher.match(descriptors1, descriptors3, None)
matches2 = sorted(matches2, key=lambda x: x.distance, reverse=False)
good_matches2 = int(len(matches2) * GOOD_MATCH_PERCENT)
matches2 = matches2[:good_matches2]  # Remove weak matches

# Image 2 - Image 3 Matcher
matches3 = matcher.match(descriptors2, descriptors3, None)
matches3 = sorted(matches3, key=lambda x: x.distance, reverse=False)
good_matches3 = int(len(matches3) * GOOD_MATCH_PERCENT)
matches3 = matches3[:good_matches3]  # Remove weak matches

# Drawing Matches
img_matches1 = cv2.drawMatches(img1, kp1, img2, kp2, matches1[0:MAX_MATCHES], None)
img_matches2 = cv2.drawMatches(img1, kp1, img3, kp3, matches2[0:MAX_MATCHES], None)
img_matches3 = cv2.drawMatches(img2, kp2, img3, kp3, matches3[0:MAX_MATCHES], None)

plt.figure(2)
plt.subplot(311), plt.imshow(img_matches1, cmap='gray'), plt.title("Image 1 - Image 2")
plt.subplot(312), plt.imshow(img_matches2, cmap='gray'), plt.title("Image 1 - Image 3")
plt.subplot(313), plt.imshow(img_matches3, cmap='gray'), plt.title("Image 2 - Image 3")
plt.show()

# Best Match Result : Img1 - Img2
points1 = np.zeros((len(matches1), 2), dtype=np.float32)
points2 = np.zeros((len(matches1), 2), dtype=np.float32)

for i, match in enumerate(matches1):
    points1[i, :] = kp1[match.queryIdx].pt
    points2[i, :] = kp2[match.trainIdx].pt

h, mask = cv2.findHomography(points2, points1, cv2.RANSAC)  # Compute Homography
img1_height, img1_width, img1_channels = img1.shape
img2_height, img2_width, img2_channels = img2.shape
im2Aligned = cv2.warpPerspective(img2, h, (img2_width + img1_width, img2_height))  # Align Img2

stitched_Image12 = np.copy(im2Aligned)  # Stitch Img 1 with Aligned Img 2
stitched_Image12[0:img1_height, 0:img1_width] = img1

plt.figure(3)
plt.imshow(stitched_Image12, cmap='gray'), plt.title("Image 1 - Image 2 Stiched")
plt.show()

# Repeating the above steps for Stiching: stitched_Image12 - Image 3
stitched_Image12 = stitched_Image12[:, :1343]
kp12, descriptors12 = orbObj.detectAndCompute(stitched_Image12, None)
matches12 = matcher.match(descriptors12, descriptors3, None)
matches12 = sorted(matches12, key=lambda x: x.distance, reverse=False)
good_matches12 = int(len(matches12) * GOOD_MATCH_PERCENT)
matches12 = matches12[:good_matches12]  # Remove weak matches

# Drawing Matches
img_matches12 = cv2.drawMatches(stitched_Image12, kp12, img3, kp3, matches12[0:MAX_MATCHES], None)
plt.figure(4)
plt.imshow(img_matches12, cmap='gray'), plt.title("Stiched Image 12 - Image 3 Matches")
plt.show()

# Stiching Images:

points1 = np.zeros((len(matches12), 2), dtype=np.float32)
points2 = np.zeros((len(matches12), 2), dtype=np.float32)

for i, match in enumerate(matches12):
    points1[i, :] = kp12[match.queryIdx].pt
    points2[i, :] = kp3[match.trainIdx].pt

h123, mask123 = cv2.findHomography(points2, points1, cv2.RANSAC)  # Compute Homography
img12_height, img12_width, img12_channels = stitched_Image12.shape
img3_height, img3_width, img3_channels = img3.shape
im3Aligned = cv2.warpPerspective(img3, h123, (img12_width + img3_width, img3_height))
stitched_Image123 = np.copy(im3Aligned)  # Stitch Img 12 with Aligned Img 3
stitched_Image123[0:img12_height, 0:img12_width] = stitched_Image12

plt.figure(5)
plt.imshow(stitched_Image123, cmap='gray'), plt.title("Image 1 - Image 2 - Image 3 Stiched")
plt.show()

stitched_Image123_noblck = np.copy(stitched_Image123)
stitched_Image123_noblck = stitched_Image123_noblck[:, :1830]
cv2.imwrite('stiched_image.jpg', stitched_Image123_noblck, [cv2.IMWRITE_JPEG_QUALITY, 80])

plt.figure(6)
plt.subplot(2, 1, 1), plt.imshow(stitched_Image123, cmap='gray'), plt.title("Image 1 - Image 2 - Image 3 Stiched")
plt.subplot(2, 1, 2), plt.imshow(stitched_Image123_noblck, cmap='gray'), plt.title("No black -Image 1 - Image 2 - "
                                                                                "Image 3 Stiched")
plt.show()

# SECTION 2

obj = cv2.imread('object.jpg')
img1 = cv2.imread('clutter01.jpg')
img2 = cv2.imread('clutter02.jpg')
img3 = cv2.imread('clutter03.jpg')
img4 = cv2.imread('clutter04.jpg')

plt.figure(1)
plt.subplot(151), plt.imshow(img1[:, :, ::-1]), plt.title("Clutter 1")
plt.subplot(152), plt.imshow(img2[:, :, ::-1]), plt.title("Clutter 2")
plt.subplot(153), plt.imshow(img3[:, :, ::-1]), plt.title("Clutter 3")
plt.subplot(154), plt.imshow(img4[:, :, ::-1]), plt.title("Clutter 4")
plt.subplot(155), plt.imshow(obj[:, :, ::-1]), plt.title("Object")
plt.show()

# Computing descriptors and keypoints using SIFT
siftObj = cv2.SIFT_create()  # Create SIFT Object
kp1, descriptors1 = siftObj.detectAndCompute(img1, None)
kp2, descriptors2 = siftObj.detectAndCompute(img2, None)
kp3, descriptors3 = siftObj.detectAndCompute(img3, None)
kp4, descriptors4 = siftObj.detectAndCompute(img4, None)
kp5, descriptors5 = siftObj.detectAndCompute(obj, None)

# Too many descriptors and keypoints => define function

def flann_with_sift(image1, d1, keyp1, image2, d2, keyp2):
    FLANN_INDEX_KDTREE = 1
    index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
    search_params = dict(checks=100)
    flann_obj = cv2.FlannBasedMatcher(index_params, search_params)
    matches = flann_obj.knnMatch(d1, d2, 2)

    # Filter matches with Lowe's ratio test(src: opencv.com - tutorial_feature_flann_matcher)
    thresh = 0.67
    valid_matches = []
    for m, n in matches:
        if m.distance < thresh * n.distance:
            valid_matches.append(m)

    if len(valid_matches) < 10:
        print(f"Valid matches: {len(valid_matches)} - Not enough matches")
    else:
        img_matched = np.empty((max(image1.shape[0], image2.shape[0]), image1.shape[1] + image2.shape[1], 3),
                               dtype=np.uint8)
        cv2.drawMatches(image1, keyp1, image2, keyp2, valid_matches, img_matched,
                        flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
        plt.figure(), plt.imshow(img_matched[:, :, ::-1]), plt.title(
            f"Matched images with Flann and SIFT")  # Draw Matches

        points1 = np.zeros((len(valid_matches), 2), dtype=np.float32)
        points2 = np.zeros((len(valid_matches), 2), dtype=np.float32)
        for i, match in enumerate(valid_matches):
            points1[i, :] = keyp1[match.queryIdx].pt
            points2[i, :] = keyp2[match.trainIdx].pt
        h, mask = cv2.findHomography(points2, points1, cv2.RANSAC)
        imHeight, imWidth, channels = image1.shape
        imAligned = cv2.warpPerspective(image2, h, (imWidth, imHeight))
        #Draw Rectangles
        cont_image = np.copy(imAligned)
        cont_image = cv2.cvtColor(cont_image, cv2.COLOR_BGR2GRAY)
        contours, hierarchy = cv2.findContours(cont_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        cv2.drawContours(image1, contours, -1, (0, 0, 255), 5)
        plt.figure()
        plt.subplot(1, 2, 1), plt.imshow(image1[:, :, ::-1]), plt.title("Original")
        plt.subplot(1, 2, 2), plt.imshow(imAligned[:,:,::-1]), plt.title("Homography")
        plt.show()

flann_with_sift(img1, descriptors1, kp1, obj, descriptors5, kp5)
flann_with_sift(img2, descriptors2, kp2, obj, descriptors5, kp5)
flann_with_sift(img3, descriptors3, kp3, obj, descriptors5, kp5)
flann_with_sift(img4, descriptors4, kp4, obj, descriptors5, kp5)


import importlib
import io
import math
import os
import typing
from enum import Enum

import discord
import humanize
from discord.ext import commands
from jishaku.functools import executor_function
from PIL import Image

import common.image_utils as image_utils
import common.utils as utils

class ImageCMDs(commands.Cog, name="Image"):
    """A series of commands for manipulating images in certain ways."""

    def __init__(self, bot):
        self.bot: utils.SeraphimBase = bot

    def get_size(self, image: io.BytesIO):
        old_pos = image.tell()
        image.seek(0, os.SEEK_END)
        size = image.tell()
        image.seek(old_pos, os.SEEK_SET)

        return size

    @executor_function
    def pil_compress(self, image, ext, flags):
        try:
            pil_image = Image.open(image)
            compress_image = io.BytesIO()

            if (
                flags.ori_ext in ("gif", "webp")
                and ext not in ("gif", "webp")
                and pil_image.is_animated
            ):
                raise commands.BadArgument(
                    "Cannot convert an animated image to this file type!"
                )

            if flags.shrink:
                width = pil_image.width
                height = pil_image.height

                if width > 1920 or height > 1920:
                    bigger = max(width, height)
                    factor = math.ceil(bigger / 1920)
                    pil_image = pil_image.reduce(factor=factor)

            if ext == "jpeg":
                if pil_image.mode != "RGB":
                    pil_image = pil_image.convert("RGB")
                pil_image.save(
                    compress_image, format=ext, quality=flags.quality, optimize=True
                )
            elif ext in ("gif", "png"):
                pil_image.save(compress_image, format=ext, optimize=True)
            elif ext == "webp":
                pil_image.save(
                    compress_image,
                    format=ext,
                    minimize_size=True,
                    quality=flags.quality,
                )
            else:
                compress_image.close()
                raise commands.BadArgument("Invalid file type!")

            compress_image.seek(0, os.SEEK_SET)

            return compress_image

        except:
            compress_image.close()
            raise
        finally:
            pil_image.close()

    @executor_function
    def pil_resize(
        self,
        image,
        ext,
        percent: typing.Optional[float],
        width: typing.Optional[int],
        height: typing.Optional[int],
        filter: int,
    ):
        resized_image = io.BytesIO()

        try:
            pil_image = Image.open(image)

            ori_width = pil_image.width
            ori_height = pil_image.height

            if percent:
                new_width = math.ceil(pil_image.width * (percent / 100))
                new_height = math.ceil(pil_image.height * (percent / 100))
            elif bool(width) ^ bool(height):
                if width:
                    new_width = width
                    percent = width / pil_image.width
                    new_height = math.ceil(pil_image.height * percent)
                else:
                    new_height = height
                    percent = height / pil_image.height
                    new_width = math.ceil(pil_image.width * percent)
            else:
                new_width = width
                new_height = height

            pil_image = pil_image.resize((new_width, new_height), filter)

            pil_image.save(resized_image, format=ext)
            resized_image.seek(0, os.SEEK_SET)

            return resized_image, ori_width, ori_height, new_width, new_height
        except:
            resized_image.close()
            raise
        finally:
            pil_image.close()

    class ImageFilters(Enum):
        # what Pillow should have done
        NEAREST = 0
        NONE = 0
        BOX = 4
        BILINEAR = 2
        LINEAR = 2
        HAMMING = 5
        BICUBIC = 3
        CUBIC = 3
        LANCZOS = 1
        ANTIALIAS = 1

    def str_to_filter(self, argument: str):
        try:
            return self.ImageFilters[argument.upper()].value
        except KeyError:
            raise commands.BadArgument(f"Invalid filter `{argument}` provided!")

    class CompressFlags(commands.FlagConverter):
        # TODO: move flag checks into a flag converter thing
        shrink: bool = True
        format: str = "default"
        quality: int = 70

    @commands.command(aliases=["image_compress"])
    async def img_compress(
        self, ctx, url: typing.Optional[image_utils.URLToImage], *, flags: CompressFlags
    ):
        """Compresses down the image given.
        It must be an image of type GIF, JPG, PNG, or WEBP. It must also be under 8 MB.
        Image quality will take a hit, and the image will shrink down if it's too big (unless you specify to not shrink the image).
        Flags:
        shrink: <true/false> (specifies to shrink the image - it will by default)
        format: <format> (converts the image to the specified format, and it must be 'gif, jpg, png, or webp' \
        - the resulting image will be in the same format as the original by default)
        quality: <number> (specifies quality from 0-100, only works with JPG and WEBP files, default is 70)"""

        if flags.format == "default":
            img_format = "default"
        else:
            img_type_checker = image_utils.ImageTypeChecker
            img_format = await img_type_checker.convert(
                img_type_checker, ctx, flags.format
            )

        if not 0 <= flags.quality <= 100:
            raise commands.BadArgument("Quality must be a number between 0-100!")

        if not url:
            url = image_utils.image_from_ctx(ctx)

        async with ctx.channel.typing():
            image_data = await image_utils.get_file_bytes(
                url, 8388608, equal_to=False
            )  # 8 MiB

            try:
                ori_image = io.BytesIO(image_data)

                mimetype = discord.utils._get_mime_type_for_image(image_data)
                ext = mimetype.split("/")[1]
                flags.ori_ext = ext  # yes, this is dirty

                if img_format != "default":
                    ext = img_format

                ori_size = self.get_size(ori_image)
                compress_image = await self.pil_compress(ori_image, ext, flags)
                compressed_size = self.get_size(compress_image)

            finally:
                del image_data
                if ori_image:
                    ori_image.close()

            try:
                com_img_file = discord.File(compress_image, f"image.{ext}")

                content = (
                    f"Original Size: {humanize.naturalsize(ori_size, binary=True)}\n"
                    + "Reduced Size:"
                    f" {humanize.naturalsize(compressed_size, binary=True)}\n"
                    + "Size Saved:"
                    f" {round(((1 - (compressed_size / ori_size)) * 100), 2)}%"
                )
            except:
                compress_image.close()
                raise

        await ctx.reply(content=content, file=com_img_file)

    class ConvertFlags(commands.FlagConverter):
        shrink: bool = False
        quality: int = 80

    @commands.command(aliases=["image_convert"])
    async def img_convert(
        self,
        ctx,
        url: typing.Optional[image_utils.URLToImage],
        img_type: image_utils.ImageTypeChecker,
        *,
        flags: ConvertFlags,
    ):
        """Converts the given image into the specified image type.
        Both the image and the specified image type must be of type GIF, JP(E)G, PNG, or WEBP. The image must also be under 8 MB.
        Flags:
        shrink: <true/false> (specifies to shrink the image - it won't by default)
        quality: <number> (specifies quality from 0-100, only works with JPG and WEBP files, default is 80)
        """

        if not 0 <= flags.quality <= 100:
            raise commands.BadArgument("Quality must be a number between 0-100!")

        if not url:
            url = image_utils.image_from_ctx(ctx)

        async with ctx.channel.typing():
            image_data = await image_utils.get_file_bytes(
                url, 8388608, equal_to=False
            )  # 8 MiB

            try:
                ori_image = io.BytesIO(image_data)

                mimetype = discord.utils._get_mime_type_for_image(image_data)
                flags.ori_ext = mimetype.split("/")[1]
                ext = img_type

                converted_image = await self.pil_compress(ori_image, ext, flags)
            finally:
                del image_data
                if ori_image:
                    ori_image.close()

            try:
                convert_img_file = discord.File(converted_image, f"image.{ext}")
            except:
                converted_image.close()
                raise

        await ctx.reply(file=convert_img_file)

    class ResizeFlags(commands.FlagConverter):
        percent: typing.Optional[float]
        width: typing.Optional[int]
        height: typing.Optional[int]
        filter: str = "BILINEAR"

    @commands.command(aliases=["image_resize"])
    async def img_resize(
        self, ctx, url: typing.Optional[image_utils.URLToImage], *, flags: ResizeFlags
    ):
        """Resizes the image as specified by the flags.
        The image must be of type GIF, JP(E)G, PNG, or WEBP. The image must also be under 8 MB.

        Required flags (one of these three must be present):
        percent: <percent> (specifies the percent to reduce it to - whole numbers with no %, like '50', please.)
        width: <width> (specifies the width to reduce it to - it must be a whole number and greater than 0.)
        height: <height> (specifies the height to reduce it to - it must be a whole number and greater than 0.)

        Optional flags:
        filter: <filter> (specifies which resampling filter to use while downsizing - see \
        https://pillow.readthedocs.io/en/stable/handbook/concepts.html#concept-filters for the filters and which \
        one is best for you. Default is Bilinear.)
        """

        filter = self.str_to_filter(flags.filter)

        if not url:
            url = image_utils.image_from_ctx(ctx)

        if not (flags.percent or flags.width or flags.height):
            raise commands.BadArgument("No resizing arguments passed!")

        if flags.percent and (flags.width or flags.height):
            raise commands.BadArgument(
                "You cannot have a percentage and a width/height at the same time!"
            )

        if flags.percent and flags.percent <= 0:
            raise commands.BadArgument("The percent must be greater than 0!")

        if flags.width and flags.width <= 0:
            raise commands.BadArgument("The width must be greater than 0!")

        if flags.height and flags.height <= 0:
            raise commands.BadArgument("The height must be greater than 0!")

        async with ctx.channel.typing():
            image_data = await image_utils.get_file_bytes(
                url, 8388608, equal_to=False
            )  # 8 MiB

            try:
                ori_image = io.BytesIO(image_data)

                mimetype = discord.utils._get_mime_type_for_image(image_data)
                ext = mimetype.split("/")[1]

                (
                    resized_image,
                    ori_width,
                    ori_height,
                    new_width,
                    new_height,
                ) = await self.pil_resize(
                    ori_image,
                    ext,
                    flags.percent,
                    flags.width,
                    flags.height,
                    filter,
                )
                resize_size = self.get_size(resized_image)

                if resize_size > 8388608:
                    resized_image.close()
                    del resized_image
                    raise commands.BadArgument("Resulting image was over 8 MiB!")
            finally:
                del image_data
                if ori_image:
                    ori_image.close()

            try:
                resized_img_file = discord.File(resized_image, f"image.{ext}")

                content = (
                    f"Original Image Dimensions: {ori_width}x{ori_height}\n"
                    + f"New Image Dimensions: {new_width}x{new_height}\n"
                    + "Resized To:"
                    f" {flags.percent or round(((new_width / ori_width) * 100), 2)}%\n"
                    + "New Image Size:"
                    f" {humanize.naturalsize(resize_size, binary=True)}"
                )
            except:
                resized_image.close()
                raise

        await ctx.reply(content=content, file=resized_img_file)

async def setup(bot):
    importlib.reload(utils)
    importlib.reload(image_utils)

    await bot.add_cog(ImageCMDs(bot))


from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor,as_completed,wait
from concurrent import futures
import time
import requests

# 官方文档：https://docs.python.org/zh-cn/3.8/library/concurrent.futures.html#module-concurrent.futures

urls = ['http://www.tencent.com','http://www.google.com/','http://www.kugou.com/']

def jisuan_b(num):
    print("b_time is ：{}。that you num is {}\n".format(time.time(),num))
    return "this is return "

def get_for_content(res):
    r = requests.get(url=res)
    # print(r.text)
    return res

with futures.ThreadPoolExecutor(max_workers=1) as f :
    start_time = time.time()
    # res = f.submit(jisuan_b,'1')          # submit()方法的返回值为一个future对象。此对象可以调用result()方法获取返回值，
    # print(res.result())                 # result函数，实际返回的是回调函数的返回值。result方法本身是阻塞的

    thread_list = []
    for x in urls:
        thread_list.append(f.submit(get_for_content,x))
    # print(wait(thread_list,return_when=FIRST_COMPLETED))              # wait 函数的作用是使主线程阻塞。使满足设定的时候再进行正常执行。
                                            # wait 有三个状态：FIRST_COMPLETED，FIRST_EXCEPTION，ALL_COMPLETED
                                                # FIRST_COMPLETED：只要有一个完成的任务(线程)，就直接的返回，不再进行阻塞。
                                                # FIRST_EXCEPTION：当发生第一个异常的时候退出。如果没有异常的话，就相当于ALL_COMPLETED
                                                # ALL_COMPLETED：当所有的任务(线程)完成的时候退出

    print("执行结束")

    # for x in as_completed(thread_list):     # as_completed函数的作用是接收：executor返回的future对象列表。
                                                # 实际为执行完成的线程返回的furure对象，也就是说安装线程完成的顺序一个一个进行迭代

    #     print("请求的链接为",x.result())     # 然后使主线程阻塞，如果thread_list中有执行完成的线程的话。会yeid这个线程的result对象。直到所有的线程都执行结束为止
    #                                         # 先完成的线程会先通知主线程。(ps.第二个参数为timeout)
    # print("耗时为：{}".format(time.time()-start_time))


import cv2 as cv
import numpy as np

left_window = 'Task 4 - left'
right_window = 'Task 4 - right'

# create window for left camera
cv.namedWindow(left_window)

# create window for right camera
cv.namedWindow(right_window)

# read in imagaes
img_l = cv.imread('imgs/combinedCalibrate/aL09.bmp')
img_r = cv.imread('imgs/combinedCalibrate/aR09.bmp')
gray = cv.cvtColor(img_l,cv.COLOR_BGR2GRAY)
shape = (gray.shape[1],gray.shape[0])

cv.imshow(left_window,img_l)
cv.imshow(right_window,img_r)
cv.waitKey(0)

# read in intrinsic params
fs_read_l = cv.FileStorage('params/left_cam.yml',cv.FILE_STORAGE_READ)
mat_l = fs_read_l.getNode("intrinsic").mat()
dist_l = fs_read_l.getNode("distortion").mat()
fs_read_l.release()

fs_read_r = cv.FileStorage('params/right_cam.yml',cv.FILE_STORAGE_READ)
mat_r = fs_read_r.getNode("intrinsic").mat()
dist_r = fs_read_r.getNode("distortion").mat()
fs_read_r.release()

fs_read = cv.FileStorage('params/stereo.yml',cv.FILE_STORAGE_READ)
R = fs_read.getNode('R').mat()
T = fs_read.getNode('T').mat()
fs_read.release()

# rectify images
R1,R2,P1,P2,Q,roi1,roi2 = cv.stereoRectify(mat_l,dist_l,mat_r,dist_r,shape,R,T)

map_l1, map_l2 = cv.initUndistortRectifyMap(mat_l,dist_l,R1,P1,shape,5)
map_r1, map_r2 = cv.initUndistortRectifyMap(mat_l,dist_l,R1,P1,shape,5)

rect_img_l = cv.remap(img_l,map_l1,map_l2,cv.INTER_LINEAR)
rect_img_r = cv.remap(img_r,map_r1,map_r2,cv.INTER_LINEAR)

diff_l = cv.absdiff(img_l,rect_img_l)
diff_r = cv.absdiff(img_r,rect_img_r)

def drawLines(img,color):
    x0 = -10
    x1 = 800
    for k in [1,2,3]:
        y = 100 * k
        image = cv.line(img,(x0,y),(x1,y),color,2)
    return image

rect_img_r = drawLines(rect_img_r,(0,0,255))
rect_img_l = drawLines(rect_img_l,(0,255,0))

cv.imshow(left_window,rect_img_l)
cv.imshow(right_window,rect_img_r)
cv.waitKey(0)

cv.imshow(left_window,diff_l)
cv.imshow(right_window,diff_r)
cv.waitKey(0)

cv.destroyAllWindows()
print('Program has ended')