import logging
import time
from functools import partial
from subprocess import call

from mininet.cli import CLI
from mininet.log import info, setLogLevel
from mininet.net import Mininet
from mininet.node import RemoteController, OVSKernelSwitch
from mininet.link import TCLink, OVSLink

logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)

CONTROLLER_IP = "127.0.0.1"
CONTROLLER_PORT = 6653
OPENFLOW_PROTOCOL = 'OpenFlow14'
IP_BASE = "10.0.88.0/24"
DPID_BASE = 1000
setLogLevel('info')

if __name__ == '__main__':

    # ---------- clean previous setup  -----------------------------
    call(["mn", "-c"])

    # ----------topology inputs -----------------------------
    # Core network topology
    # in
    # De Maesschalck, S., Colle, D., Lievens, I., Pickavet, M., Demeester, P., Mauz, C., ... & Derkacz, J.(2003).
    # Pan-European optical transport networks: An availability-based comparison.
    # Photonic Network Communications, 5(3), 203 - 225.
    switch_names = {1: "lon", 2: "ams", 3: "bru", 4: "par", 5: "ham",
                    6: "fra", 7: "str", 8: "zur", 9: "lyn", 10: "ber",
                    11: "mun", 12: "mil", 13: "pra", 14: "vie", 15: "zag",
                    16: "rom"}
    switch_link_matrix = [(1, 2), (1, 4), (2, 3), (2, 5), (3, 4),
                          (3, 6), (4, 7), (4, 9), (5, 6), (5, 10),
                          (6, 7), (6, 11), (7, 8), (8, 9), (8, 12),
                          (10, 11), (10, 13), (11, 12), (11, 14), (12, 16),
                          (13, 14), (14, 15), (15, 16)]
    host_count_per_switch = 1

    # ---------- initialize network  -----------------------------
    OpenFlow14Switch = partial(OVSKernelSwitch, protocols=OPENFLOW_PROTOCOL)

    net = Mininet(ipBase=IP_BASE)
    net.addController("c0", controller=RemoteController, link=OVSLink, ip=CONTROLLER_IP, port=CONTROLLER_PORT)

    try:
        # ----------switches and hosts -----------------------------
        switches = {}
        links = {}
        for sw_ind in switch_names:
            name = switch_names[sw_ind]
            dpid = DPID_BASE + sw_ind

            sw = net.addSwitch(name, dpid="%x" % dpid, cls=OpenFlow14Switch)
            switches[sw_ind] = sw
            for host_index in range(1, host_count_per_switch + 1):
                host = net.addHost(name + '%02d' % host_index)
                net.addLink(sw, host)

        # ---------- create links -----------------------------
        for item in switch_link_matrix:
            sw1 = switches[item[0]]
            sw2 = switches[item[1]]
            link = net.addLink(sw1, sw2)
            links[item] = link

        lon = net.getNodeByName("lon")
        nat = net.addNAT("nat", connect=lon)
        nat_ip = nat.params['ip'].split('/')[0]
        host = net.addHost('ids')
        net.addLink(lon, host)

        print(f'NAT ip: {nat_ip}')

        info('*** Starting network\n')
        net.start()

        time.sleep(2)

        for host in net.hosts:
            if host.inNamespace:
                host.setDefaultRoute('via %s' % nat_ip)
        nat.configDefault()
        info('*** Running CLI\n')
        CLI(net)

        info('*** Stopping network')
        net.stop()
    except Exception as err:
        info(err)

        net.stop()


from marvin import Bot

class ResumeAnalyzer:
    def __init__(self):
        self.bot = Bot(
            name="ResumeAnalyzer",
            instructions=("Analyze a set of resumes for a specific job position, "
                          "assign a score for each resume.")
        )

    async def analyze_resumes(self, job_position, resumes):
        scores = []
        for resume in resumes:
            name = await self.bot.say(f"Get the name of the candidate for resume {resume} without any other prose")
            result = await self.bot.say(f"Assign a score to the resume {resume} for the job position '{job_position}'")
            score = await self.bot.say(f"Extract only the score of the candidate for {result.content} without any other prose")
            scores.append({
                "name": name.content,
                "score": score.content,
                "analysis": result.content
            })
        return scores


import glob
import os
import subprocess
from pathlib import Path

def find_files():
    download_folder = Path(Path.home(), 'Downloads', 'Test')
    files = glob.glob('fmb_*.html', root_dir=download_folder)
    print(files)
    script_dir = Path(Path.home(), "work", "fmb")
    os.chdir(script_dir)
    for file in files:
        file_with_path = Path(download_folder, file)
        pdf_file = str(file_with_path).replace(".html", ".pdf")
        if not Path(pdf_file).exists():
            script = Path(os.getcwd(), "jsscript.js")
            script = "jsscript.js"
            cmd = f"node {script} {file_with_path}"
            print(cmd)
            result = subprocess.run(["node", script, str(file_with_path)], capture_output=True, text=True)
            print(result)
        else:
            print(f"{pdf_file} : already processed")

if __name__ == "__main__":
    find_files()


import bpy
import math

from dataclasses import dataclass
from ..util import console_out, bad_mesh
from .model_assets import model_util, armature, mesh, materials

class Model:
    def __init__(self, nn, file_path, settings):
        self.file_path = file_path
        self.model = nn.model
        self.settings = settings
        self.format = settings.format
        self.bone_groups = [bone.group for bone in self.model.bones]
        self.bone_names = nn.bones
        self.model_name = nn.name
        self.model_name_strip = self.model_name[:-4]
        self.texture_names = nn.textures
        self.armature = None
        self.material_list_blender = []
        self.group_names = []
        self.mat_names = []
        self.mesh_names = []

    def execute(self):
        print("Making a Model------------------------------------")
        message = "Making" + " " + self.model_name
        print(message + " " * (50 - len(message)) + "|")

        console_out("Making Armature...", armature.make_armature, self)
        console_out("Generating Names...", model_util.make_names, self)
        if self.settings.keep_bones_accurate:
            console_out("Making Accurate Bones...", armature.make_bones_accurate, self)
        else:
            console_out("Making Pretty Bones...", armature.make_bones_pretty, self)

        bpy.ops.object.mode_set(mode="POSE")  # pose bone stuff here
        console_out("Making Bone Groups...", armature.make_bone_groups, self)
        if self.settings.hide_null_bones:
            console_out("Hiding Null Bones...", armature.hide_null_bones)

        bpy.ops.object.mode_set(mode="OBJECT")  # return to normal
        if self.settings.simple_materials:
            console_out("Making Simple Materials...", materials.material_simple, self)
        else:
            console_out("Making Accurate Materials...", materials.material_complex, self)

        console_out("Making Meshes...", mesh.make_mesh, self)

@dataclass
class ModelData:
    name: str
    center: tuple
    radius: float
    bones: list
    materials: list
    meshes: tuple
    geometry: tuple
    bone_depth: int
    bone_used: list

@dataclass
class MeshTypes:
    simple_opaque: list
    complex_opaque: list
    simple_alpha: list
    complex_alpha: list

class ModelInfo:
    def __init__(self, settings, arma):
        self.settings = settings
        self.format = settings.format
        self.armature = arma
        self.name = ""
        self.mesh_list = []
        self.center = (0, 0, 0)
        self.radius = 0.0
        self.bone = []
        self.bone_depth = 0
        self.bone_used = []
        self.material = []
        self.meshes = []

    def generic(self):
        arma = self.armature
        name = arma.name
        mesh_list = [a for a in arma.children if a.type == "MESH" and len(a.data.polygons) > 0]
        self.mesh_list = mesh_list

        if name.endswith("." + self.format[-1].lower() + "no"):
            pass
        else:
            name = name + "." + self.format[-1].lower() + "no"
        self.name = name

        print("Getting Model Data--------------------------------")
        message = "Making" + " " + name

        print(message + " " * (50 - len(message)) + "|")

    def get_empty_rig(self):
        bone, bone_depth, bone_used = console_out("Getting Bone Info...", armature.get_bones, self)
        material = console_out("Getting Material Info...", materials.get_materials, self)
        meshes = MeshTypes([], [], [], [])
        meshes, geometry = console_out("Generating Geometry...", mesh.get_geometry, (meshes, self.settings, self))
        return ModelData(self.name, (0, 0, 0), 0, bone, material, meshes, geometry, bone_depth, bone_used)

    def get_generic(self):
        self.center, self.radius = console_out("Generating Bounds...", armature.get_render_data, self.mesh_list)
        self.bone, self.bone_depth, self.bone_used = console_out("Getting Bone Info...", armature.get_bones, self)
        self.material = console_out("Getting Material Info...", materials.get_materials, self)
        self.meshes = console_out("Getting Mesh Info...", mesh.get_meshes, self.mesh_list)

    def alpha_fix(self):
        material = self.material
        meshes = self.meshes
        mat_name_list = [a.name for a in material.material_list]
        for m in meshes:
            mat_index = mat_name_list.index(m.material_name)
            mat = material.material_list[mat_index]
            m.material_name = mat_index
            if m.bpy_obj.data.vertex_colors:
                mesh_v_alpha = [0, 0, 0, 0] * len(m.bpy_obj.data.vertex_colors[0].data)
                m.bpy_obj.data.vertex_colors[0].data.foreach_get("color", mesh_v_alpha)
                mesh_v_alpha = set(mesh_v_alpha[3::4])
                if len(mesh_v_alpha) > 1 or 1 > list(mesh_v_alpha)[0]:
                    m.opaque = False
                    continue
            for tex in mat.texture_list:
                img_alpha = set(tex.name.image.pixels[::][3::4])
                # sometimes bpy.data.images[mat.image].pixels[3::4] as a slice issue (warning it's not an int?)
                if len(img_alpha) > 1 or (list(img_alpha) and 1 > list(img_alpha)[0]):
                    # check if the texture has pixels (if texture path was valid but files were moved)
                    m.opaque = False
                    continue
            if 1 > mat.alpha:
                m.opaque = False

    def build_mesh_list(self):
        simple_opaque = []
        complex_opaque = []
        simple_alpha = []
        complex_alpha = []

        for m in self.meshes:
            if m.opaque:
                if len(m.bone_names) > 1:
                    complex_opaque.append(m)
                else:
                    simple_opaque.append(m)
            else:
                if len(m.bone_names) > 1:
                    complex_alpha.append(m)
                else:
                    simple_alpha.append(m)

        self.meshes = MeshTypes(simple_opaque, complex_opaque, simple_alpha, complex_alpha)

    def model(self):
        self.generic()

        name = self.name
        mesh_list = self.mesh_list

        if not mesh_list:
            return self.get_empty_rig()

        quad_count = console_out("Checking Faces...", model_util.check_meshes, mesh_list)
        if quad_count:
            bad_mesh("NN Model Exporter")
            return False
        self.get_generic()

        self.alpha_fix()

        self.build_mesh_list()

        meshes, geometry = console_out("Generating Geometry...", mesh.get_geometry, (self.meshes, self.settings, self))

        if self.format[-1] == "G":
            for me, geo in zip([meshes.simple_opaque, meshes.complex_opaque, meshes.simple_alpha, meshes.complex_alpha],
                               geometry):
                if me:  # first level is complex_opaque / simple_opaque etc.
                    for m, g in zip(me, geo.faces):
                        has_col = g.colours_type
                        if has_col:
                            self.material.material_list[m.material_name].v_col = True
        else:
            for me, geo in zip([meshes.simple_opaque, meshes.complex_opaque, meshes.simple_alpha, meshes.complex_alpha],
                               geometry):
                if me:  # first level is complex_opaque / simple_opaque etc.
                    for m, g in zip(me, geo.faces):
                        has_col = g.colours
                        if has_col:
                            self.material.material_list[m.material_name].v_col = True

        return ModelData(
            name, self.center, self.radius, self.bone, self.material, meshes, geometry, self.bone_depth, self.bone_used)

    def execute(self):
        return self.model()


# cython: language_level=3
from flask import session
from flask_jwt_extended import verify_jwt_in_request, get_jwt_identity
from flask_jwt_extended.exceptions import (NoAuthorizationError,
                                           InvalidHeaderError)
from flask_socketio import disconnect, emit

def init_socketio_api(app):
    """Initialize SocketIO APIs"""
    from flask_socketio import SocketIO
    app.socketio = SocketIO(
        app,
        cors_allowed_origins=app.config['ALLOWED_ORIGIN'])

    @app.socketio.on('connect')
    def connect_handler():
        try:
            verify_jwt_in_request()
        except (NoAuthorizationError, InvalidHeaderError):
            emit('error', {
                'event': 'connect',
                'status': 'error',
                'error_message': 'Invalid or not provided access token.'
            })
            disconnect()
        session['current_user_email'] = get_jwt_identity()

    from .livestream import livestream  # noqa


#!/usr/bin/env python3

import argparse
import re

def removeSentencePunc(line):
    line = re.sub("[,.?;:!\"]|\[|\]", "", line) #remove sentence punctuations
    line = re.sub("--", " ", line) #removes all instances of double hyphens
    line = re.sub("[']([\w']+[-]?[\w']*)[']", r'\1', line) #removes instances of 'word' words
    line = line.lower() #allows for correct alphabetizing later
    return line

def characterDictionaryCreator(character, dictionary):
    if character not in dictionary:
        dictionary[character] = {}
    return dictionary

def wordCounter(block, dictionary, character):
    block = removeSentencePunc(block) #send dialogue to have punc removed
    for word in block.split():
        if word not in dictionary[character]:
            dictionary[character][word] = 1
        else:
            dictionary[character][word] += 1
    return dictionary

def dictionarySorter(dictionary):
    characterNameSort = sorted(dictionary)
    totalNumWords = 0
    for characterName in characterNameSort: #sort the character names
        totalCharWords = 0
        wordList = dictionary[characterName]
        sortedWordList = sorted(wordList)
        print (str(characterName) + ":")
        for word in sortedWordList: #sort the words spoken by the character
            totalCharWords += dictionary[characterName][word]
            totalNumWords += dictionary[characterName][word]
            print("\t" + str(word) + ": " + str(dictionary[characterName][word]) + "\n")
        print ("The total number of words spoken by this character is:\n\t" + str(totalCharWords))
    print("The total number of words spoken by all characters are:\n\t" + str(totalNumWords))
    return

def writeToCSV(dictionary):
    with open("word_count.csv", mode = 'w') as WRITE_FILE:
        characterNameSort = sorted(dictionary)
        for characterName in characterNameSort:
            wordList = dictionary[characterName]
            sortedWordList = sorted(wordList)
            for word in sortedWordList:
                WRITE_FILE.write("{0},{1},{2}\n".format(characterName, word, dictionary[characterName][word]))
    WRITE_FILE.close()
    return

def main():
    parser = argparse.ArgumentParser(description='Open .txt files')
    parser.add_argument('-r', '--readFile', metavar='FILE', type=str, nargs=1, help='One .txt file to be opened and word counted')

    args = parser.parse_args()

    with open(args.readFile[0]) as READ_FILE: #open file
        character_dict = {}
        characterName = ""

        for i, line in enumerate(READ_FILE):
            if i<4:
                continue
            if re.search("^\n", line) == None: #non-empty line
                if re.search("^\s+", line) == None: #the line is a character
                    index = len(line)-1
                    characterName = line[:index].lower()
                    character_dict = characterDictionaryCreator(characterName, character_dict)
                else: #block of dialogue
                    character_dict = wordCounter(line, character_dict, characterName)

        dictionarySorter(character_dict)
        writeToCSV(character_dict)

    READ_FILE.close()

    return

if(__name__== "__main__"):
    main()


import pytest

from flask import url_for
from pytest_flask import fixtures
from flask_login import login_user, current_user, logout_user

from mdt_app.models import *
from mdt_app.main.forms import *

@pytest.mark.usefixtures('client_class', 'db_session', 'populate_db')
class TestIndex:
    def setup(self):
        user1 = User.query.first()
        login_user(user1)

    def test_page_load(self):
        assert self.client.get(url_for('main.index')).status_code == 200

@pytest.mark.developing
@pytest.mark.usefixtures('client_class', 'db_session', 'populate_db')
class TestCaseList:
    def setup(self):
        self.meeting = Meeting.query.first()

    def test_page_load(self):
        request = self.client.get(url_for('main.case_list'))

        assert request.status_code == 200

        # Cases are listed with patient name
        assert b"PATIENT" in request.data
        assert b"ENTRY" in request.data

    def test_meeting_filter(self):
        request = self.client.get(url_for('main.case_list',
                                          meeting=self.meeting.date))
        html = str(request.data).replace('\\n', '').replace('\\t', '')

        # Cases are listed with patient name, without cases for 16th Oct)
        assert "PATIENT" in html
        assert "DUMMY" in html
        assert "16-Oct-2050" not in html

        # status bar
        assert "33% Discussed" in html
        assert "To be discussed: 2 / 3" in html
        assert "to be actioned: 1 / 3" in html
        assert "& actioned: 0 / 3" in html

    def test_push_cases_no_future(self):
        request = self.client.get(url_for('main.case_list',
                                          meeting=self.meeting.date,
                                          push_cases=1))

        assert b'no meetings exist after this one' in request.data

    def test_push_cases_patient_clash(self):
        early_meeting = Meeting.query.filter_by(date='2050-10-16').first()
        request = self.client.get(url_for('main.case_list',
                                          meeting=early_meeting.date,
                                          push_cases=1))

        assert b'was not moved as patient also has a case' in request.data

    def test_push_cases_success(self, db_session):
        all_meetings = Meeting.query.all()
        new_meeting = Meeting(date='2050-12-30',
                              id=all_meetings[-1].id + 1)
        db_session.add(new_meeting)
        db_session.commit()
        request = self.client.get(url_for('main.case_list',
                                          meeting=self.meeting.date,
                                          push_cases=1))

        assert b'Case for patient Third DUMMY was moved to ' in request.data

@pytest.mark.usefixtures('client_class', 'db_session', 'populate_db')
class TestCaseCreate:
    def setup(self):
        meeting = Meeting.query.filter_by(date='2050-10-16').first()
        consultant = User.query.filter_by(initials='AC').first()
        self.form = CaseForm(case_id=-1,
                             patient_id=1,
                             meeting=meeting.id,
                             consultant=consultant.id,
                             mdt_vcmg='MDT',
                             medical_history='another set of medical history',
                             question='another question here',
                             clinic_code='')

    def test_page_load(self):
        req_pass = self.client.get(url_for('main.case_create', patient_id=1))
        req_no_id = self.client.get(url_for('main.case_create', patient_id=''))

        assert req_pass.status_code == 200
        # title
        assert b"Cases for Test PATIENT 12345678" in req_pass.data
        # flashed message
        assert b"Date of birth (age):" in req_pass.data

        assert req_no_id.status_code == 404, 'no id, page not found'

    # login works within scope of function but not in the view
    # need to make a login fixture?
    @pytest.mark.xfail
    def test_case_add(self):
        # login user for created_by
        user1 = User.query.first()
        login_user(user1)
        print(current_user)
        # request
        request = self.client.post(url_for('main.case_create', patient_id=1),
                                   data=self.form.data)

        assert request.status_code == 302

        assert b"another set of medical history" in request.data


from django.shortcuts import render
from django.http import JsonResponse, HttpResponse

from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http  import require_GET, require_POST

from django.apps import apps

from .forms import UserForm, StudentForm, TeacherForm

# Create your views here.

@csrf_exempt
@require_POST
def create_user(request):
    User = apps.get_model('users', 'User')

    form = UserForm(request.POST)

    if form.is_valid():
        user = form.save()
        usr = {'id': user.id, 'username': user.username, 'first_name': user.first_name,
               'last_name': user.last_name, 'is_teacher': user.is_teacher}

        return JsonResponse({'user': usr})

    return JsonResponse({'error': form.errors}, status=400)

@csrf_exempt
@require_POST
def create_student(request):
    User = apps.get_model('users', 'User')
    Student = apps.get_model('users', 'Student')

    form = StudentForm(request.POST)

    if form.is_valid():
        student = Student.objects().filter(user_id=form.cleaned_data['user_id']).first()

        if student == None:
            student = form.save()

        stud = {'id': student.id, 'user_id': student.user.id, 'class_name_id': student.class_name.id}

        return JsonResponse({'student': student})

    return JsonResponse({'error': form.errors}, status=400)

@csrf_exempt
@require_POST
def create_teacher(request):
    User = apps.get_model('users', 'User')
    Teacher = apps.get_model('users', 'Student')

    form = TeacherForm(request.POST)

    if form.is_valid():
        teacher = Teacher.objects().filter(user_id=form.cleaned_data['user_id']).first()

        if teacher == None:
            teacher = form.save()

        teach = {'id': teacher.id, 'user_id': teacher.user.id, 'subject_id': teacher.subject.id}

        return JsonResponse({'teacher': teach})

    return JsonResponse({'error': form.errors}, status=400)

@require_GET
def students_list(request):
    User = apps.get_model('users', 'User')
    Student = apps.get_model('users', 'Student')
    Class = apps.get_model('classes', 'Class')

    students = Student.objects().all().values('id', 'user_id', 'class_id')

    result = []

    for s in students:
        user = User.objects().filter(id=s['user_id']).first()
        s_class = Class.objects().filter(id=s['class_name_id'])

        student = {'id': s.id, 'first_name': user.first_name, 'last_name': user.last_name,
                   'class_number': s_class.parallel, 'class_letter': s_class.letter}

        result.append(student)

    return JsonResponse({'students': result})

@require_GET
def teachers_list(request):
    User = apps.get_model('users', 'User')
    Teacher = apps.get_model('users', 'Student')
    Subject = apps.get_model('classes', 'Subject')

    teachers = Teacher.objects().all().values('id', 'user_id', 'subject_id')

    result = []

    for t in teachers:
        user = User.objects().filter(id=t['user_id']).first()
        subject = Subject.objects().filter(id=t['subject_id'])

        teacher = {'id': t.id, 'first_name': user.first_name, 'last_name': user.last_name,
                   'subject_name': subject.name, 'subject_class': subject.class_name.id}

        result.append(teacher)

    return JsonResponse({'teachers': result})

@require_GET
def search_by_name(request):
    User = apps.get_model('users', 'User')

    users = User.objects.filter(username__contains=request.GET['name']).values('id', 'username', 'first_name', 'last_name')[:int(request.GET['limit'])]
    return JsonResponse({'users': list(users)})

@require_GET
def search_by_id(request):
    User = apps.get_model('users', 'User')

    users = User.objects.filter(id=request.GET['id']).values('id', 'username', 'first_name', 'last_name')[:int(request.GET['limit'])]
    return JsonResponse({'users': list(users)})


import cv2
import numpy as np
import os
import argparse
import math
from operator import xor

clear = lambda: os.system('cls')

class Scaler:
    angle = 0.0
    def __init__(self, min, max, a, b):
        self.min = min
        self.max = max
        self.a = a
        self.b = b
        print("Min: " + str(self.min))
        print("Max: " + str(self.max))
        print("A: " + str(self.a))
        print("B: " + str(self.b))
    def scaleX(self, x):
        angle = (((self.b-self.a)*(x-self.min))/(self.max-self.min))+self.a
        return angle

leftScaler = Scaler(min=0.0, max=160.0, a=-21.80140949, b=0)
rightScaler = Scaler(min=160.0, max=320.0, a=0, b=21.80140949)

def callback(value):
    pass

def setup_trackbars(range_filter):
    cv2.namedWindow("Trackbars", 0)

    for i in ["MIN", "MAX"]:
        v = 0 if i == "MIN" else 255
        for j in range_filter:
            cv2.createTrackbar("%s_%s" % (j, i), "Trackbars", v, 255, callback)
    cv2.createTrackbar("MIN_CANNY", "Trackbars", 0, 500, callback)
    cv2.createTrackbar("MAX_CANNY", "Trackbars", 280, 500, callback)

def get_arguments():
    ap = argparse.ArgumentParser()
    ap.add_argument('-f', '--filter', required=True,
                    help='Range Filter. RGB or HSV')
    ap.add_argument('-hsv', '--hsvvalues', required=False,
                    help='Filter Values')
    ap.add_argument('-i', '--image', required=False,
                    help='Path to the image')
    ap.add_argument('-w', '--webcam', required=False,
                    help='Use webcam', action='store_true')
    ap.add_argument('-cvinf', '--cvinformation', required=False,
                    help='Use if you want to apply the contours, centroids, and area',
                    action='store_true')
    ap.add_argument('-wi', '--webcamindex', required=False,
                    help='Webcam Index')
    ap.add_argument('-p', '--preview', required=False,
                    help='Show a preview of the image after applying the mask',
                    action='store_true')
    ap.add_argument('-cs', '--camerasetsettings', required=False,
                    help='Set camera settings',
                    action='store_true')
    ap.add_argument('-cg', '--cameragetsettings', required=False,
                    help='Get camera settings',
                    action='store_true')
    args = vars(ap.parse_args())

    if not xor(bool(args['image']), bool(args['webcam'])):
        ap.error("Please specify only one image source")

    if not args['filter'].upper() in ['RGB', 'HSV']:
        ap.error("Please speciy a correct filter.")

    return args

def get_trackbar_values(range_filter):
    values = []
    for i in ["MIN", "MAX"]:
        for j in range_filter:
            v = cv2.getTrackbarPos("%s_%s" % (j, i), "Trackbars")
            values.append(v)
    v = cv2.getTrackbarPos("MIN_CANNY", "Trackbars")
    values.append(v)
    v = cv2.getTrackbarPos("MAX_CANNY", "Trackbars")
    values.append(v)
    return values

def labelCenter(image, c):
    # Places a red circle on the centers of contours
    cx = 0
    M = cv2.moments(c)
    if M['m00'] is not 0 and M['m10'] is not 0 and M['m01']:
        cx = int(M['m10'] / M['m00'])
        cy = int(M['m01'] / M['m00'])
        cv2.circle(image,(cx,cy), 3, (0,0,255), -1)
    # Draw the countour number on the image
    return image, cx

def contoursFinding(image, canny_min_thresh, canny_max_thresh):

    #Grayscaling that original image
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    #Finding canny edges
    edged = cv2.Canny(gray, canny_min_thresh, canny_max_thresh)

    #Find the contours
    im2, contours, hierarchy = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    #Returning the contours

    return contours

def getCenterCentroid(c1x, c2x):
    minX = min(c1x,c2x)
    maxX = max(c1x,c2x)
    distance = maxX - minX
    center = distance/2 + minX
    return center

def labelingCentroidsAndAreas(image, contours):
    sortedContours =  sorted(contours, key=cv2.contourArea, reverse=True)
    cxs = []
    center = 0;
    for (i, c) in enumerate(sortedContours):
        if i is 0 or i is 1:
            blank, cx = labelCenter(image, c)
            area = cv2.contourArea(c)
            cv2.putText(image, "Area: " + str(area), (image.shape[0]-80, image.shape[1]-100 + i*15)
                        , cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 2)
            cxs.append(cx)

    if len(cxs) >=  2:
            center = getCenterCentroid(cxs[0], cxs[1])
            center = int(center)
            angle = 0
            cv2.circle(image,(center,200), 3, (0,0,255), -1)
            cv2.putText(image, "Center X:  " + str(center), (image.shape[0]-250, image.shape[1]-100),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 2)
            if center >= 160:
                angle = rightScaler.scaleX(x=center)
            else:
                angle = leftScaler.scaleX(x=center)
            cv2.putText(image, "Angle: " + str(angle), (image.shape[0]-320, image.shape[1]-85),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 2)

    cv2.drawContours(image, contours, -1, (0, 255, 0), 1)
    #dilation = cv2.dilate(blank_image, kernel, iterations = 3)
    cv2.imshow('CV Information', image)

def main():
    args = get_arguments()
    range_filter = args['filter'].upper()
    if args['image']:
        image = cv2.imread(args['image'])

        if range_filter == 'RGB':
            frame_to_thresh = image.copy()
        else:
            frame_to_thresh = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    else:
        if args['webcamindex']:
            int_webcam_index = int(args['webcamindex'])
            camera = cv2.VideoCapture(int_webcam_index)
            camera.set(3, 320)
            camera.set(4, 240)
            camera.set(5, 15)
            if args['camerasetsettings']:
                camera.set(11, 2)
                camera.set(12, 120)
                camera.set(13, 1)
                camera.set(15, -7)

        else:
            camera = cv2.VideoCapture(0)
            camera.set(3, 320)
            camera.set(4, 240)
            camera.set(5, 15)

            if args['camerasetsettings']:
                camera.set(11, 2)
                camera.set(12, 120)
                camera.set(13, 1)
                camera.set(15, -7)
    if args['hsvvalues'] is None:
        setup_trackbars(range_filter)

    while True:
        if args['webcam']:
            ret, image = camera.read()

            if range_filter == 'RGB':
                frame_to_thresh = image.copy()
            else:
                frame_to_thresh = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
        if args['hsvvalues']:
            arrvalues = args['hsvvalues'].split(',')
            v1_min = arrvalues[0]
            v2_min = arrvalues[1]
            v3_min = arrvalues[2]
            v1_max = arrvalues[3]
            v2_max = arrvalues[4]
            v3_max = arrvalues[5]
            min_canny = arrvalues[6]
            max_canny = arrvalues[7]
            min_canny = int(min_canny)
            max_canny = int(max_canny)

            mask = cv2.inRange(frame_to_thresh, (int(v1_min), int(v2_min), int(v3_min)), (int(v1_max), int(v2_max), int(v3_max)))
        else:
            v1_min, v2_min, v3_min, v1_max, v2_max, v3_max, min_canny, max_canny = get_trackbar_values(range_filter)
            mask = cv2.inRange(frame_to_thresh, (v1_min, v2_min, v3_min), (v1_max, v2_max, v3_max))

        blank_image_preview = np.zeros((image.copy().shape[0], image.shape[1], 3))
        blank_image_cvinfo = np.zeros((image.copy().shape[0]+100, image.shape[1]+100, 3))
        if args['preview']:
            preview = cv2.bitwise_and(image, image, mask=mask)
            cv2.imshow("Preview", preview)
        else:
            image = cv2.flip(image, 1)
            cv2.imshow("Original", image)

            thresh = cv2.flip(thresh, 1)
            cv2.imshow("Thresh", thresh)

        if args['cvinformation']:
            filtered_img = cv2.bitwise_and(image, image, mask=mask)
            contours = contoursFinding(filtered_img, min_canny, max_canny)
            labelingCentroidsAndAreas(blank_image_cvinfo, contours)
            if args['cameragetsettings']:
                print ( " CV_CAP_PROP_FORMAT:  "+str(camera.get(9)) + "" )
                print ( " CV_CAP_PROP_MODE:  "+str(camera.get(10)) + "" )
                print ( " CV_CAP_PROP_BRIGHTNESS:  "+str(camera.get(11)) + "" )
                print ( " CV_CAP_PROP_CONTRAST:  "+str(camera.get(12)) + "" )
                print ( " CV_CAP_PROP_SATURATION:  "+str(camera.get(13)) + "" )
                print ( " CV_CAP_PROP_HUE:  "+str(camera.get(14)) + "" )
                print ( " CV_CAP_PROP_GAIN:  "+str(camera.get(15)) + "" )
                print ( " CV_CAP_PROP_EXPOSURE:  "+str(camera.get(16)) + "" )
        if cv2.waitKey(1) == 13:
            break

    camera.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()


# Import des modules/ packages utiles au fonctionnement des routes
# Relation templates et routes, manipulation requêtes et réponses HTTP, envoi de messages flash, redirection
from flask import render_template, request, flash, redirect
# Pour la gestion des comptes utilisateurs
from flask_login import login_user, logout_user, current_user, login_required
# Import de la variable app
from BibPart.app import app
# Import pour la pagination
from .constantes import RESULTATS_PAR_PAGE
# Import permettant d'utiliser l'opérateur booléen or
from sqlalchemy import or_
# Import de l'ensemble des modèles de classe utiles
from .modeles.donnees import Oeuvre, Partition, Compositeur, Type, Instrument, Forme, Institution_conservation
from .modeles.utilisateurs import Utilisateur

# ROUTES PERMETTANT L'AFFICHAGE DES PAGES ACCUEIL ET EN SAVOIR PLUS

@app.route("/")
def accueil():
    """
    Route permettant l'affichage de la page accueil
    :returns : affichage du template accueil.html
    :rtype: page html
    """
    oeuvres = Oeuvre.query.filter(Oeuvre.id_oeuvre).all()
    partitions = Partition.query.filter(Partition.id_partition).all()
    compositeurs = Compositeur.query.filter(Compositeur.id_compositeur).all()
    return render_template("pages/accueil.html", nom="BibPart", oeuvres=oeuvres, partitions=partitions,
                           compositeurs=compositeurs)

@app.route("/ensavoirplus")
def ensavoirplus():
    """ Route permettant l'affichage de la page En savoir plus
    :returns : affichage du template ensavoirplus.html
    :rtype: page html
    """
    return render_template("pages/ensavoirplus.html")

# ROUTES PERMETTANT L'AFFICHAGE DES INDEX

@app.route("/index_oeuvres")
def index_oeuvres():
    """ Route permettant l'affichage de l'index des oeuvres
    :returns: affichage du template index_oeuvres.html
    :rtype: page html
    """
    alloeuvres = Oeuvre.query.all()

    if len(alloeuvres) == 0:
        return render_template("pages/index_oeuvres.html", var_groupe_oeuvres=alloeuvres)
    else:
        page = request.args.get("page", 1)

        if isinstance(page, str) and page.isdigit():
            page = int(page)
        else:
            page = 1

    alloeuvres = Oeuvre.query.order_by(Oeuvre.titre_oeuvre).paginate(page=page, per_page=RESULTATS_PAR_PAGE)
    return render_template("pages/index_oeuvres.html", nom="BibPart", var_groupe_oeuvres=alloeuvres)

@app.route("/index_partitions")
def index_partitions():
    """ Route permettant l'affichage de l'index des partitions
    :returns: affichage du template index_partitions.html
    :rtype: page html
    """
    allpartitions = Partition.query.all()

    if len(allpartitions) == 0:
        return render_template("pages/index_oeuvres.html", var_groupe_partitions=allpartitions)
    else:
        page = request.args.get("page", 1)

        if isinstance(page, str) and page.isdigit():
            page = int(page)
        else:
            page = 1

    allpartitions = Partition.query.order_by(Partition.titre_partition).paginate(page=page, per_page=RESULTATS_PAR_PAGE)
    return render_template("pages/index_partitions.html", nom="BibPart", var_groupe_partitions=allpartitions)

@app.route("/index_compositeurs")
def index_compositeurs():
    """ Route permettant l'affichage de l'index des compositeurs
    :returns: affichage du template index_compositeurs.html
    :rtype: page html
    """
    allcompositeurs = Compositeur.query.all()

    if len(allcompositeurs) == 0:
        return render_template("pages/index_oeuvres.html", var_groupe_partitions=allcompositeurs)
    else:
        page = request.args.get("page", 1)

        if isinstance(page, str) and page.isdigit():
            page = int(page)
        else:
            page = 1

    allcompositeurs = Compositeur.query.order_by(Compositeur.nom_compositeur).paginate(page=page,
                                                                                per_page=RESULTATS_PAR_PAGE)
    return render_template("pages/index_compositeurs.html", nom="BibPart", var_groupe_compositeurs=allcompositeurs)

# ROUTES PERMETTANT L'AFFICHAGES DES NOTICES

@app.route("/notice_oeuvre/<int:id_oeuvre>")
def notice_oeuvre(id_oeuvre):
    """
    Route permettant d'afficher la notice d'une oeuvre
    :param id_oeuvre: id de l'oeuvre
    :type id_oeuvre: int
    :return: affichage du template notice_oeuvre.html
    :rtype: page html
    """
    unique_oeuvre = Oeuvre.query.get(id_oeuvre)
    compositeur = unique_oeuvre.compositeurs
    forme = unique_oeuvre.formes
    type = unique_oeuvre.types
    instrument = unique_oeuvre.instruments
    partition = unique_oeuvre.partitions
    return render_template("pages/notice_oeuvre.html", nom="BibPart", var_oeuvre_unique=unique_oeuvre,
                           var_compositeur=compositeur, var_forme=forme, var_type=type, var_instrument=instrument,
                           var_partition=partition)

@app.route("/notice_partition/<int:id_partition>")
def notice_partition(id_partition):
    """
    Route permettant d'afficher la notice d'une partition
    :param id_partition: id de la partition
    :type id_partition: int
    :returns: affichage du template notice_partition.html
    :rtype: page html
    """
    unique_partition = Partition.query.get(id_partition)
    audio = unique_partition.oeuvres
    institution = unique_partition.institutions_conservation
    oeuvre = unique_partition.oeuvres
    return render_template("pages/notice_partition.html", nom="BibPart", var_partition_unique=unique_partition,
                           var_audio=audio, var_institution=institution, var_oeuvre=oeuvre)

@app.route("/notice_compositeur/<int:id_compositeur>")
def notice_compositeur(id_compositeur):
    """
    Route permettant d'afficher la notice d'un compositeur
    :param id_compositeur: id du compositeur
    :type id_compositeur: int
    :returns: affichage du template notice_compositeur.html
    :rtype: page html
    """
    unique_compositeur = Compositeur.query.get(id_compositeur)
    oeuvrecompo = unique_compositeur.oeuvres
    return render_template("pages/notice_compositeur.html", nom="BibPart", var_compositeur_unique=unique_compositeur,
                           var_oeuvrecompo=oeuvrecompo)

# ROUTES PERMETTANT UNE RECHERCHE RAPIDE ET AVANCÉE

@app.route("/recherche", methods=["GET"])
def recherche():
    """
       Route permettant de faire une recherche rapide sur les notices d'oeuvre
       :returns : affichage des templates correspondant aux barres de recherches et aux résultats de la recherche rapide
       :rtype: pages html
       """
    # Gestion de la page courante
    page = request.args.get("page", 1)

    if isinstance(page, str) and page.isdigit():
        page = int(page)
    else:
        page = 1

    keyword = request.args.get("keyword", None)
    # Création d'une liste vide permettant de stocker les mots-clefs s'ils existent, sinon elle reste vide
    resultats = []

    # Méthode "GET" utilisée : les mots clefs recherchés apparaîssent dans l'URL
    if keyword:
        resultats = Oeuvre.query.filter(or_(
            Oeuvre.id_oeuvre.like("%{}%".format(keyword)),
            Oeuvre.titre_oeuvre.like("%{}%".format(keyword)),
            Oeuvre.date_oeuvre.like("%{}%".format(keyword)),
            Oeuvre.compositeurs.has(Compositeur.nom_compositeur.like("%{}%".format(keyword))),
            Oeuvre.types.has(Type.label_type.like("%{}%".format(keyword))),
            Oeuvre.formes.has(Forme.label_forme.like("%{}%".format(keyword))))
        ).paginate(page=page, per_page=RESULTATS_PAR_PAGE)
        titre = "Résultat pour la recherche `" + keyword + "`"
    return render_template("pages/recherche.html", resultats=resultats, titre=titre, keyword=keyword)

@app.route('/rechercheavancee', methods=["POST", "GET"])
def rechercheavancee():
    """
    Route permettant de faire une recherche avancée
    :returns : affichage des templates correspondant aux formulaires et aux résultats de la recherche avancée
    :rtype: pages html
    """
    # Gestion de la page courante
    page = request.args.get("page", 1)

    if isinstance(page, str) and page.isdigit():
        page = int(page)
    else:
        page = 1

    # Condition pour la méthode "POST" : cette méthode permet de ne pas inscrire les données dans l'URL, contrairement
    # à la méthode "GET"
    if request.method == "POST":
        # Création de 3 listes vides permettant de stocker par type de notice (oeuvre, partition, compositeur)
        # les mots-clefs s'ils existent, sinon elles restent vides
        resultatsA = []
        resultatsB = []
        resultatsC = []
        keyword = request.form.get("keyword", None)
        # Variable appelée dans le template des résultats pour la recherche avancée
        titre = "Résultat(s) de la recherche avancée"

        questionOeuvre = Oeuvre.query
        questionPartition = Partition.query
        questionCompositeur = Compositeur.query

        # Notice oeuvre
        titre_oeuvre = request.form.get("titreOeuvre", None)
        compositeur_oeuvre = request.form.get("compoOeuvre", None)
        date_oeuvre = request.form.get("dateOeuvre", None)
        type_oeuvre = request.form.get("typeOeuvre", None)
        forme_oeuvre = request.form.get("formeOeuvre", None)
        instrument_oeuvre = request.form.get("instrumentOeuvre", None)

        # Notice partition
        titre_partition = request.form.get("titrePartition", None)
        sous_titre_partition = request.form.get("soustitrePartition", None)
        format_partition = request.form.get("formatPartition", None)
        page_partition = request.form.get("nbpagePartition", None)
        statut_partition = request.form.get("statutPartition", None)
        institution_partition = request.form.get("nomInstitutionConservation", None)

        # Notice compositeur
        prenom_compo = request.form.get("prenomCompo", None)
        nom_compo = request.form.get("nomCompo", None)
        naissance_compo = request.form.get("naissanceCompo", None)
        mort_compo = request.form.get("mortCompo", None)

        # Notice oeuvre
        if titre_oeuvre:
            resultatsA = questionOeuvre.filter(Oeuvre.titre_oeuvre.like("%{}%".format(titre_oeuvre)))
        if compositeur_oeuvre:
            resultatsA = questionOeuvre.filter(
                Oeuvre.compositeurs.has(Compositeur.nom_compositeur.like("%{}%".format(compositeur_oeuvre))))
        if date_oeuvre:
            resultatsA = questionOeuvre.filter(Oeuvre.date_oeuvre.like("%{}%".format(date_oeuvre)))
        if type_oeuvre:
            resultatsA = questionOeuvre.filter(Oeuvre.types.has(Type.label_type.like("%{}%".format(type_oeuvre))))
        if forme_oeuvre:
            resultatsA = questionOeuvre.filter(Oeuvre.formes.has(Forme.label_forme.like("%{}%".format(forme_oeuvre))))
        if instrument_oeuvre:
            resultatsA = questionOeuvre.filter(Oeuvre.instruments.any(
                Instrument.label_instrument.like("%{}%".format(instrument_oeuvre))))

        # Notice partition
        if titre_partition:
            resultatsB = questionPartition.filter(Partition.titre_partition.like("%{}%".format(titre_partition)))
        if sous_titre_partition:
            resultatsB = questionPartition.filter(
                Partition.nom_sous_partie_partition.like("%{}%".format(sous_titre_partition)))
        if format_partition:
            resultatsB = questionPartition.filter(Partition.format_partition.like("%{}%".format(format_partition)))
        if page_partition:
            resultatsB = questionPartition.filter(Partition.page_partition.like("%{}%".format(page_partition)))
        if statut_partition:
            resultatsB = questionPartition.filter(Partition.statut_partition.like("%{}%".format(statut_partition)))
        if institution_partition:
            resultatsB = questionPartition.filter(Partition.institutions_conservation.has(
                Institution_conservation.nom_institution_conservation.like("%{}%".format(institution_partition))))

        # Notice compositeur
        if prenom_compo:
            resultatsC = questionCompositeur.filter(Compositeur.prenom_compositeur.like("%{}%".format(prenom_compo)))
        if nom_compo:
            resultatsC = questionCompositeur.filter(
                Compositeur.nom_compositeur.like("%{}%".format(nom_compo)))
        if naissance_compo:
            resultatsC = questionCompositeur.filter(
                Compositeur.annee_naissance_compositeur.like("%{}%".format(naissance_compo)))
        if mort_compo:
            resultatsC = questionCompositeur.filter(Compositeur.annee_mort_compositeur.like("%{}%".format(mort_compo)))

        if resultatsA:
            resultatsA = resultatsA.paginate(page=page)
        if resultatsB:
            resultatsB = resultatsB.paginate(page=page)
        if resultatsC:
            resultatsC = resultatsC.paginate(page=page)
        return render_template("pages/rechercheavancee.html", keyword=keyword, titre=titre, resultatsA=resultatsA,
                               resultatsB=resultatsB, resultatsC=resultatsC)
    return render_template("pages/rechercheavancee.html", nom="BibPart")

# ROUTES PERMETTANT L'INSCRIPTION, LA CONNEXION, LA DÉCONNEXION

@app.route("/register", methods=["GET", "POST"])
def inscription():
    """
    Route permettant l'inscription d'un utilisateur
    :returns: redirection vers template accueil.html si succès ou vers template inscription.html si erreur
    :rtype: pages html
    """
    if request.method == "POST":
        # Application de la fonction creer présente dans le fichier utilisateurs.py
        statut, donnees = Utilisateur.creer(
            login=request.form.get("login", None),
            email=request.form.get("email", None),
            nom=request.form.get("nom", None),
            motdepasse=request.form.get("motdepasse", None))

        if statut is True:
            flash("Enregistrement effectué. Identifiez-vous maintenant", "success")
            return redirect("/")
        else:
            flash("Les erreurs suivantes ont été rencontrées : " + ", ".join(donnees) + ".", "danger")
            return render_template("pages/inscription.html")
    else:
        return render_template("pages/inscription.html")

@app.route("/connexion", methods=["POST", "GET"])
def connexion():
    """
    Route permettant la connexion d'un utilisateur
    :returns: redirection vers template accueil.html si succès ou vers template connexion.html si erreur
    :rtype: pages html
    """
    if current_user.is_authenticated is True:
        flash("Vous êtes déjà connecté-e", "info")
        return redirect("/")

    if request.method == "POST":
        # Application de la fonction identification présente dans le fichier utilisateurs.py
        user = Utilisateur.identification(
            login=request.form.get("login", None),
            motdepasse=request.form.get("motdepasse", None))
        if user:
            flash("Connexion réussie", "success")
            login_user(user)
            return redirect("/")
        else:
            flash("Le login ou le mot de passe est incorrect.", "danger")

    return render_template("pages/connexion.html")

@app.route("/deconnexion", methods=["POST", "GET"])
def deconnexion():
    """
    Route permettant la déconnexion d'un utilisateur
    :returns: redirection vers template accueil.html
    :rtype: page html
    """
    if current_user.is_authenticated is True:
        logout_user()
    flash("Vous êtes déconnecté-e", "info")
    return redirect("/")

# ROUTES PERMETTANT L'AJOUT DE NOTICES

@app.route("/accueil_ajout", methods=["GET", "POST"])
def accueil_ajout():
    """
    Route permettant l'affichage de la page d'accueil pour l'ajout
    :return : affichage du template accueil_ajout.html
    :rtype : page html
    """
    return render_template("pages/accueil_ajout.html", nom="BibPart")

@app.route("/ajout_compositeur", methods=["GET", "POST"])
def ajout_compositeur():
    """
    Route permettant l'ajout d'un compositeur et les données qui lui sont associées dans la BDD
    :return: affichage du template ajout_compositeur.html
    :rtype: page html
    """
    if request.method == "POST":
        statut, donnees_compo = Compositeur.ajouter_compositeur(
            ajout_nom_compo=request.form.get("ajout_nom_compo", None),
            ajout_prenom_compo=request.form.get("ajout_prenom_compo", None),
            ajout_naissance_compo=request.form.get("ajout_naissance_compo", None),
            ajout_mort_compo=request.form.get("ajout_mort_compo", None),
            ajout_bio_compo=request.form.get("ajout_bio_compo", None),
            ajout_portrait_compo=request.form.get("ajout_portrait_compo", None))

        if statut is True:
            flash("Ajout réussi !", "success")
            return render_template("pages/ajout_compositeur.html", nom="BibPart")

        else:
            flash("Les erreurs suivantes ont été rencontrées : " + ", ".join(donnees_compo), "danger")
            return render_template("pages/ajout_compositeur.html")

    return render_template("pages/ajout_compositeur.html", nom="BibPart")

@app.route("/ajout_forme", methods=["GET", "POST"])
def ajout_forme():
    """
    Route permettant l'ajout d'une forme dans la BDD
    :return: affichage du template ajout_forme.html
    :rtype: page html
    """
    if request.method == "POST":
        statut, donnees_forme = Forme.ajouter_forme(
            ajout_label_forme=request.form.get("ajout_label_forme", None))

        if statut is True:
            flash("Ajout réussi !", "success")
            return render_template("pages/ajout_forme.html", nom="BibPart")

        else:
            flash("Les erreurs suivantes ont été rencontrées : " + ", ".join(donnees_forme), "danger")
            return render_template("pages/ajout_forme.html", nom="BibPart")

    return render_template("pages/ajout_forme.html", nom="BibPart")

@app.route("/ajout_institution", methods=["GET", "POST"])
def ajout_institution():
    """
    Route permettant l'ajout d'une institution de conservation dans la BDD
    :return: affichage du template ajout_institution.html
    :rtype: page html
    """
    if request.method == "POST":
        statut, donnees_insti = Institution_conservation.ajouter_institution(
            ajout_nom_institution=request.form.get("ajout_nom_institution", None),
            ajout_ville_institution=request.form.get("ajout_ville_institution", None))

        if statut is True:
            flash("Ajout réussi !", "success")
            return render_template("pages/ajout_institution.html", nom="BibPart")

        else:
            flash("Les erreurs suivantes ont été rencontrées : " + ", ".join(donnees_insti), "danger")
            return render_template("pages/ajout_institution.html", nom="BibPart")
    return render_template("pages/ajout_institution.html", nom="BibPart")

@app.route("/ajout_instrument", methods=["GET", "POST"])
def ajout_instrument():
    """
    Route permettant l'ajout d'un instrument dans la BDD
    :return : affichage du template ajout_instrument.html
    :rtype: page html
    """
    if request.method == "POST":
        labelInstrument = request.form.get("ajout_label_instrument", None)
        Instrument.ajouter_instrument(labelInstrument)

        flash("Ajout réussi !", "success")
        return render_template("pages/ajout_instrument.html", nom="BibPart")

    return render_template("pages/ajout_instrument.html", nom="BibPart")

@app.route("/ajout_oeuvre", methods=["GET", "POST"])
def ajout_oeuvre():
    """
    Route permettant l'ajout d'une oeuvre et les données qui lui sont associées dans la BDD
    :return: affichage du template ajout_oeuvre.html
    :rtype: page html
    """
    listeoeuvre = Oeuvre.query.order_by(Oeuvre.titre_oeuvre).all()
    listecompositeur = Compositeur.query.order_by(Compositeur.nom_compositeur).all()
    listetype = Type.query.order_by(Type.label_type).all()
    listeforme = Forme.query.order_by(Forme.label_forme).all()
    listeinstrument = Instrument.query.order_by(Instrument.label_instrument).all()

    if request.method == "POST":
        titreOeuvre = request.form.get("ajout_titre_oeuvre", None)
        dateOeuvre = request.form.get("ajout_date_oeuvre", None)
        audioOeuvre = request.form.get("ajout_audio_oeuvre", None)
        compoOeuvre = request.form.get("ajout_compositeur_oeuvre", None)
        typeOeuvre = request.form.get("ajout_type_oeuvre", None)
        formeOeuvre = request.form.get("ajout_forme_oeuvre", None)
        labelInstrument = request.form.get("ajout_label_instrument", None)
        recup = Compositeur.query.filter(Compositeur.nom_compositeur == compoOeuvre).first()
        recup2 = Type.query.filter(Type.label_type == typeOeuvre).first()
        recup3 = Forme.query.filter(Forme.label_forme == formeOeuvre).first()
        id_oeuvre = Oeuvre.ajouter_oeuvre(titreOeuvre, dateOeuvre, audioOeuvre, recup.id_compositeur, recup2.id_type,
                                          recup3.id_forme)
        id_instrument = Instrument.ajouter_instrument(labelInstrument)
        Instrument.association_Oeuvre_Instrument(id_oeuvre, id_instrument)

        flash("Ajout réussi !", "success")
        return render_template("pages/ajout_oeuvre.html", nom="BibPart", Listeoeuvre=listeoeuvre,
                               Listecompositeur=listecompositeur, Listetype=listetype, Listeforme=listeforme,
                               Listeinstrument=listeinstrument)

    return render_template("pages/ajout_oeuvre.html", nom="BibPart", Listeoeuvre=listeoeuvre,
                           Listecompositeur=listecompositeur, Listetype=listetype, Listeforme=listeforme,
                           Listeinstrument=listeinstrument)

@app.route("/ajout_partition", methods=["GET", "POST"])
def ajout_partition():
    """
    Route permettant l'ajout d'une partition et les données qui lui sont associées dans la BDD
    :return : affichage du template ajout_partition.html
    :rtype: page html
    """
    listepartition = Partition.query.all()
    listeoeuvre = Oeuvre.query.all()
    listeinstitution = Institution_conservation.query.all()

    if request.method == "POST":
        titrePartition = request.form.get("ajout_titre_partition", None)
        soustitrePartition = request.form.get("ajout_sous_titre_partition", None)
        formatPartition = request.form.get("ajout_format_partition", None)
        pagePartition = request.form.get("ajout_page_partition", None)
        statutPartition = request.form.get("ajout_statut_partition", None)
        visionneusePartition = request.form.get("ajout_visionneuse_partition", None)
        oeuvrePartition = request.form.get("ajout_oeuvre_partition", None)
        institutionPartition = request.form.get("ajout_institution_partition", None)
        recup = Oeuvre.query.filter(Oeuvre.titre_oeuvre == oeuvrePartition).first()
        recup2 = Institution_conservation.query.filter(
            Institution_conservation.nom_institution_conservation == institutionPartition).first()
        Partition.ajouter_partition(titrePartition, soustitrePartition, formatPartition, pagePartition, statutPartition,
                                    visionneusePartition, recup.id_oeuvre, recup2.id_institution_conservation)

        flash("Ajout réussi !", "success")
        return render_template("pages/ajout_partition.html", nom="BibPart", Listepartition=listepartition,
                               Listeoeuvre=listeoeuvre, Listeinstitution=listeinstitution)

    return render_template("pages/ajout_partition.html", nom="BibPart", Listepartition=listepartition,
                           Listeoeuvre=listeoeuvre, Listeinstitution=listeinstitution)

# ROUTES PERMETTANT LA MODIFICATION DES DONNÉES DES NOTICES

@app.route("/maj_oeuvre/<int:identifier>", methods=["GET", "POST"])
@login_required
def maj_oeuvre(identifier):
    """
    Route permettant la modification de la notice d'une oeuvre
    :param identifier: id de l'oeuvre
    :type identifier: int
    :return: redirection vers template index_oeuvres.html si succès ou vers template maj_oeuvre.html si échec
    :rtype: pages html
    """
    listecompositeur = Compositeur.query.all()
    listetype = Type.query.all()
    listeforme = Forme.query.all()
    listeinstrument = Instrument.query.all()

    # Si méthode "GET"
    if request.method == "GET":
        modif_oeuvre = Oeuvre.query.get(identifier)
        modif_oeuvre_compo = modif_oeuvre.compositeurs

        return render_template("pages/maj_oeuvre.html", oeuvre=modif_oeuvre, composi=modif_oeuvre_compo,
                               Listecompositeur=listecompositeur, Listetype=listetype, Listeforme=listeforme,
                               Listeinstrument=listeinstrument)

    # Si méthode "POST"
    else:
        # Application de la fonction modifier_oeuvre présente dans le fichier donnees.py
        statut, donnees = Oeuvre.modifier_oeuvre(
            Id_oeuvre=identifier,
            maj_titre=request.form.get("maj_titre", None),
            maj_compositeur=request.form.get("maj_compositeur", None),
            maj_date_oeuvre=request.form.get("maj_date_oeuvre", None),
            maj_forme=request.form.get("maj_forme", None),
            maj_type=request.form.get("maj_type", None),
            maj_audio=request.form.get("maj_audio", None),
            maj_instrument=request.form.get("maj_instrument", None))

        if statut is True:
            flash("Modification réussie !", "success")
            return redirect("/index_oeuvres")
        else:
            flash("Les erreurs suivantes ont été rencontrées : " + ",".join(donnees), "danger")
            modif_oeuvre = Oeuvre.query.get(identifier)
            modif_oeuvre_compo = modif_oeuvre.compositeurs

            return render_template("pages/maj_oeuvre.html", nom="BibPArt", oeuvre=modif_oeuvre,
                                   composi=modif_oeuvre_compo)

@app.route("/maj_partition/<int:identifier>", methods=["GET", "POST"])
@login_required
def maj_partition(identifier):
    """
    Route permettant la modification de la notice d'une partition
    :param identifier: id de la partition
    :type identifier: int
    :return: redirection vers template index_partitions.html si succès ou vers template maj_partition.html si échec
    :rtype: pages html
    """
    listeinstitution = Institution_conservation.query.all()
    listeoeuvre = Oeuvre.query.all()

    # Si méthode "GET"
    if request.method == "GET":
        modif_partition = Partition.query.get(identifier)

        return render_template("pages/maj_partition.html", partition=modif_partition, Listeinstitution=listeinstitution,
                               Listeoeuvre=listeoeuvre)

    # Si méthode "POST"
    else:
        # Application de la fonction modifier_partition présente dans le fichier donnees.py
        statut, donnees = Partition.modifier_partition(
            Id_partition=identifier,
            maj_titre=request.form.get("maj_titre", None),
            maj_sous_titre=request.form.get("maj_sous_titre", None),
            maj_format=request.form.get("maj_format", None),
            maj_page=request.form.get("maj_page", None),
            maj_statut=request.form.get("maj_statut", None),
            maj_institution_conservation=request.form.get("maj_institution_conservation", None),
            maj_notice_oeuvre=request.form.get("maj_notice_oeuvre", None),
            maj_visionneuse=request.form.get("maj_visionneuse", None))

        if statut is True:
            flash("Modification réussie !", "success")
            return redirect("/index_partitions")
        else:
            flash("Les erreurs suivantes ont été rencontrées : " + ", ".join(donnees), "danger")
            modif_partition = Partition.query.get(identifier)

            return render_template("pages/maj_partition.html", nom="BibPArt", partition=modif_partition)

@app.route("/maj_compositeur/<int:identifier>", methods=["GET", "POST"])
@login_required
def maj_compositeur(identifier):
    """
    Route permettant la modification de la notice d'un compositeur
    :param identifier: id du compositeur
    :type identifier: int
    :return: redirection vers template index_compositeurs.html si succès ou vers template maj_compositeur.html si échec
    :rtype: pages html
    """
    # Si méthode "GET"
    if request.method == "GET":
        modif_compositeur = Compositeur.query.get(identifier)

        return render_template("pages/maj_compositeur.html", compositeur=modif_compositeur)
    # Si méthode "POST"
    else:
        # Application de la fonction modifier_compositeur présente dans le fichier donnees.py
        statut, donnees = Compositeur.modifier_compositeur(
            Id_compositeur=identifier,
            maj_prenom=request.form.get("maj_prenom", None),
            maj_nom=request.form.get("maj_nom", None),
            maj_naissance=request.form.get("maj_naissance", None),
            maj_mort=request.form.get("maj_mort", None),
            maj_bio=request.form.get("maj_bio", None),
            maj_url=request.form.get("maj_url", None))

        if statut is True:
            flash("Modification réussie !", "success")
            return redirect("/index_compositeurs")
        else:
            flash("Les erreurs suivantes ont été rencontrées : " + ", ".join(donnees), "danger")
            modif_compositeur = Compositeur.query.get(identifier)

            return render_template("pages/maj_compositeur.html", nom="BibPArt", compositeur=modif_compositeur)

# ROUTES PERMETTANT LES SUPPRESSIONS DE NOTICES

@app.route("/supprimer_oeuvre/<int:id_oeuvre>", methods=["POST", "GET"])
@login_required
def supprimer_oeuvre(id_oeuvre):
    """
    Route permettant la suppression d'une oeuvre et de ses données dans la BDD
    :param id_oeuvre : id de l'oeuvre
    :type id_oeuvre: int
    :return: redirection vers template index_oeuvres.html si succès ou vers template supprimer_oeuvre.html si échec
    :rtype: pages html
    """
    suppr_oeuvre = Oeuvre.query.get(id_oeuvre)

    if request.method == "POST":
        # Application de la fonction supprimer_oeuvre présente dans le fichier donnees.py
        statut = Oeuvre.supprimer_oeuvre(id_oeuvre=id_oeuvre)

        if statut is True:
            flash("Suppression réussie !", "success")
            return redirect("/index_oeuvres")
        else:
            flash("La suppression a échoué. Réessayez !", "danger")
            return redirect("/")
    else:
        return render_template("pages/supprimer_oeuvre.html", nom="BibPart", suppr_oeuvre=suppr_oeuvre)

@app.route("/supprimer_partition/<int:id_partition>", methods=["POST", "GET"])
@login_required
def supprimer_partition(id_partition):
    """
    Route permettant la suppression d'une partition et de ses données dans la BDD
    :param id_partition : id de la partition
    :type id_partition: int
    :return: redirection vers template index_partitions.html si succès ou vers template supprimer_partition.html si échec
    :rtype: pages html
    """
    suppr_partition = Partition.query.get(id_partition)

    if request.method == "POST":
        # Application de la fonction supprimer_partition présente dans le fichier donnees.py
        statut = Partition.supprimer_partition(id_partition=id_partition)

        if statut is True:
            flash("Suppression réussie !", "success")
            return redirect("/index_partitions")
        else:
            flash("La suppression a échoué. Réessayez !", "danger")
            return redirect("/")
    else:
        return render_template("pages/supprimer_partition.html", nom="BibPart", suppr_partition=suppr_partition)

@app.route("/supprimer_compositeur/<int:id_compositeur>", methods=["POST", "GET"])
@login_required
def supprimer_compositeur(id_compositeur):
    """
    Route permettant la suppression d'un compositeur et de ses données dans la BDD
    :param id_compositeur : id du compositeur
    :type id_compositeur: int
    :return: redirection vers template index_compositeurs.html si succès ou vers template supprimer_compositeur.html si échec
    :rtype: pages html
    """
    suppr_compositeur = Compositeur.query.get(id_compositeur)

    if request.method == "POST":
        # Application de la fonction supprimer_compositeur présente dans le fichier donnees.py
        statut = Compositeur.supprimer_compositeur(id_compositeur=id_compositeur)

        if statut is True:
            flash("Suppression réussie !", "success")
            return redirect("/index_compositeurs")
        else:
            flash("La suppression a échoué. Réessayez !", "danger")
            return redirect("/")
    else:
        return render_template("pages/supprimer_compositeur.html", nom="BibPart", suppr_compositeur=suppr_compositeur)