#!/usr/bin/python
# coding: UTF-8

import os, sys, subprocess, uuid as unique
from lxml import etree as et
import sqlite3 as sqlite
from sqlite3 import Error

import modules.error as error

class SimpleObject(object):
    def __init__(self, is_new, uuid, dbfile):
        if is_new == True:
            if not uuid == None:
                self._uuid = uuid
            else:
                self._uuid = str(unique.uuid4())
        else:
            self._uuid = None

    @property
    def id(self): return self._id
    @property
    def uuid(self): return self._uuid

    @id.setter
    def id(self, value): self._id = value
    @uuid.setter
    def uuid(self, value): self._uuid = value

    def excuteSQL(self, dbfile, sql, values):
        print(("## Execute the SQL: features::SimpleObject::excuteSQL"))

        try:
            # Convert None objects into "Null" values in DB table.
            db_values = list()
            for value in values:
                if value == None or value == "":
                    db_values.append("NULL")
                else:
                    db_values.append(value)

            # Establish the connection to the DataBase file.
            conn = sqlite.connect(dbfile)

            if conn is not None:
                # Instantiate the cursor for query.
                cur = conn.cursor()

                # Execute the query.
                cur.execute(sql, db_values)

                # Commit the result of the query.
                conn.commit()
        except Error as e:
            # Create error messages.
            error = {
                'title': "エラーが発生しました",
                'message': "データベースに統合体の情報を挿入できませんでした。",
                'info': "SQLiteのデータベース・ファイルあるいはデータベースの設定を確認してください。",
                'icon': "Critical",
                'detailed': e.args[0]
            }
            print((e.args[0]))
            # Returns error messages.
            return(error)
        finally:
            # Finally close the connection.
            conn.close()

    def fetchOneSQL(self, dbfile, sql, keys):
        # print("## Fetch a object: "+ sql +": SimpleObject::fetchOneSQL")
        # Establish the connection between DB.
        conn = sqlite.connect(dbfile)

        try:
            if conn is not None:
                # Instantiate the cursor for query.
                cur = conn.cursor()

                # Execute the query.
                cur.execute(sql, keys)

                # Fetch one row.
                rows = cur.fetchone()
                entry = list()

                # Replace NULL values by blank.
                for row in rows:
                    if row == "NULL":
                        entry.append("")
                    else:
                        entry.append(row)

                # Get attributes from the row.
                return(entry)
            else:
                return(None)
        except Exception as e:
            err_info = "Error occus in SimpleObject::fetchOneSQL(self, dbfile , sql, keys)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

    def fetchAllSQL(self, dbfile, sql, keys):
        print("## Fetch all objects: features::SimpleObject::fetchAllSQL")

        try:
            # Establish the connection between DB.
            conn = sqlite.connect(dbfile)

            if conn is not None:
                # Instantiate the cursor for query.
                cur = conn.cursor()

                # Execute the query.
                cur.execute(sql, keys)

                # Fetch one row.
                rows = cur.fetchall()

                entries = list()

                # Replace NULL values by blank.
                for row in rows:
                    entry = list()

                    for value in row:
                        if value == "NULL":
                            entry.append("")
                        else:
                            entry.append(value)
                    entries.append(entry)

                # Get attributes from the row.
                return(entries)
            else:
                return(None)
        except Exception as e:
            err_info = "Error occus in SimpleObject::fetchAllSQL(self, dbfile , sql, keys)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

class Consolidation(SimpleObject):
    @property
    def name(self): return self._name
    @property
    def geographic_annotation(self): return self._geographic_annotation
    @property
    def temporal_annotation(self): return self._temporal_annotation
    @property
    def images(self): return self._images
    @property
    def sounds(self): return self._sounds
    @property
    def movies(self): return self._movies
    @property
    def texts(self): return self._texts
    @property
    def geometries(self): return self._geometries
    @property
    def additionalAttributes(self): return self._additionalAttributes
    @property
    def description(self): return self._description

    @name.setter
    def name(self, value): self._name = value
    @geographic_annotation.setter
    def geographic_annotation(self, value): self._geographic_annotation = value
    @temporal_annotation.setter
    def temporal_annotation(self, value): self._temporal_annotation = value
    @images.setter
    def images(self, value): self._images = value
    @sounds.setter
    def sounds(self, value): self._sounds = value
    @movies.setter
    def movies(self, value): self._movies = value
    @texts.setter
    def texts(self, value): self._texts = value
    @geometries.setter
    def geometries(self, value): self._geometries = value
    @additionalAttributes.setter
    def additionalAttributes(self, value): self._additionalAttributes = value
    @description.setter
    def description(self, value): self._description = value

    def __init__(self, is_new=True, uuid=None, dbfile=None):
        # Initialize the super class.
        # SimpleObject.__init__(self, is_new, uuid, dbfile)
        super(Consolidation, self).__init__(is_new, uuid, dbfile)

        if is_new == True and dbfile == None:
            # Initialize as the new instance.
            self._name = None
            self._geographic_annotation = None
            self._temporal_annotation = None
            self._images = list()
            self._sounds = list()
            self._movies = list()
            self._texts = list()
            self._geometries = list()
            self._additionalAttributes = list()
            self._description = None
            self._objectPath = None
        elif is_new == False and uuid != None and dbfile != None:
            # Initialize by the DB instance.
            self._initInstanceByUuid(uuid, dbfile)
        else:
            # Other unexpected case.
            return(None)

    # operation
    def _initInstanceByUuid(self, uuid, dbfile):
        print("Start -> Consolidation::_initInstanceByUuid(self, uuid, dbfile)")

        try:
            # Make the SQL statement.
            sql_select = """SELECT  id,
                                    name,
                                    geographic_annotation,
                                    temporal_annotation,
                                    description
                            FROM consolidation WHERE uuid=?"""

            # Fech one from DB.
            print("## Fetch a Consolidation: SimpleObject::fetchOneSQL")
            entry = super(Consolidation, self).fetchOneSQL(dbfile, sql_select, [uuid])

            if not entry == None:
                # Get attributes from the row.
                self._id = entry[0]
                self._uuid = uuid
                self._name = entry[1]
                self._geographic_annotation = entry[2]
                self._temporal_annotation = entry[3]
                self._images = self._getFileList(dbfile, "image")
                self._sounds = self._getFileList(dbfile, "audio")
                self._movies = self._getFileList(dbfile, "movie")
                self._texts = self._getFileList(dbfile, "text")
                self._geometries = self._getFileList(dbfile, "geometry")
                self._additionalAttributes = self._getAdditionalAttributes(dbfile)
                self._description = entry[4]
            else:
                return(None)
        except Exception as e:
            err_info = "Error occus in Consolidation::_initInstanceByUuid(self, uuid, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))
        finally:
            print("End -> Consolidation::_initInstanceByUuid(self, uuid, dbfile)")

    def dbInsert(self, dbfile):
        print("Consolidation::dbInsert(self, dbfile)")

        try:
            # Insert a new record into the database
            values = [
                self._uuid,
                self._name,
                self._geographic_annotation,
                self._temporal_annotation,
                self._description
            ]

            # Create the SQL query for inserting the new consolidation.
            sql_insert = """INSERT INTO consolidation (
                        uuid,
                        name,
                        geographic_annotation,
                        temporal_annotation,
                        description
                    ) VALUES (?,?,?,?,?)"""

            # Execute the query.
            super(Consolidation, self).excuteSQL(dbfile, sql_insert, values)

            # Insert images of the Consolidation.
            if not self._images == None:
                if len(self._images) <= 0:
                    for image in self._images: image.dbInsert(dbfile)

            # Insert sounds of the Consolidation.
            if not self._sounds == None:
                if not len(self._sounds) <= 0:
                    for sound in self._sounds: sound.dbInsert(dbfile)

            # Insert movies of the Consolidation.
            if not self._movies == None:
                if not len(self._movies) <= 0:
                    for movie in self._movies: movie.dbInsert(dbfile)

            # Insert texts of the Consolidation.
            if not self._texts == None:
                if not len(self._texts) <= 0:
                    for text in self._texts: text.dbInsert(dbfile)

            # Insert geometry of the Consolidation.
            if not self._geometries == None:
                if not len(self._geometries) <= 0:
                    for geometry in self._geometries: geometry.dbInsert(dbfile)

            # Insert additional attributes.
            if not self._additionalAttributes == None:
                if not len(self._additionalAttributes) <= 0:
                    for additionalAttribute in self._additionalAttributes:
                        additionalAttribute.dbInsert(dbfile, "consolidation", self._uuid)
        except Exception as e:
            err_info = "Error occus in Consolidation::dbInsert(self, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

    def dbUpdate(self, dbfile):
        print("consolidation::dbUpdate(self, dbfile)")

        try:
            # Insert a new record into the database
            values = [
                self._name,
                self._geographic_annotation,
                self._temporal_annotation,
                self._description,
                self._uuid
            ]

            # Create the SQL query for updating the new consolidation.
            sql_update = """UPDATE consolidation
                        SET
                            name = ?,
                            geographic_annotation = ?,
                            temporal_annotation = ?,
                            description = ?
                        WHERE uuid = ?"""

            # Execute the query.
            super(Consolidation, self).excuteSQL(dbfile, sql_update, values)

            # Update images of the Consolidation.
            if not self._images == None:
                if len(self._images) <= 0:
                    for image in self._images: image.dbUpdate(dbfile)

            # Update sounds of the Consolidation.
            if not self._sounds == None:
                if not len(self._sounds) <= 0:
                    for sound in self._sounds: sound.dbUpdate(dbfile)

            # Update sounds of the Consolidation.
            if not self._movies == None:
                if not len(self._movies) <= 0:
                    for movie in self._movies: movie.dbUpdate(dbfile)

            # Update text of the Consolidation.
            if not self._texts == None:
                if not len(self._texts) <= 0:
                    for text in self._texts: text.dbUpdate(dbfile)

            # Update geometry of the Consolidation.
            if not self._geometries == None:
                if not len(self._geometries) <= 0:
                    for geometry in self._geometries: geometry.dbUpdate(dbfile)

            # Update additional attributes.
            if not self._additionalAttributes == None:
                if not len(self._additionalAttributes) <= 0:
                    for additionalAttribute in self._additionalAttributes:
                        additionalAttribute.dbUpdate(dbfile)
        except Exception as e:
            err_info = "Error occus in Consolidation::dbUpdate(self, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

    def dbDrop(self, dbfile):
        print("Consolidation::dbDrop(self, dbfile)")

        try:
            # Dropt the exsiting entry from the DB.
            values = [self._uuid]

            # Create the SQL query for deleting the existing consolidation.
            sql_delete = """DELETE FROM consolidation WHERE uuid = ?"""

            # Execute the query.
            super(Consolidation, self).excuteSQL(dbfile, sql_delete, values)
        except Exception as e:
            err_info = "Error occus in Consolidation::dbDrop(self, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

    def _getFileList(self, dbfile, file_type):
        print("Start -> Consolidation::_getFileList(self, dbfile, file_type)")

        # Initialyze the return value.
        sop_file_list = list()

        try:
            # Get image files related to the consolidation.
            sql_select = """SELECT uuid FROM file WHERE con_id = ? AND mat_id="NULL" AND file_type=? ORDER BY id DESC;"""

            # Execute the query.
            print("## Get " + str(file_type) + " files.")
            sop_files = super(Consolidation, self).fetchAllSQL(dbfile, sql_select, [self._uuid, file_type])

            # Exit if there are no entries.
            if sop_files == None or len(sop_files) == 0: return(None)

            # Create sop image ojects from the DB table.
            for sop_file in sop_files:
                sop_file_obj = File(is_new=False, uuid=sop_file[0], dbfile=dbfile)
                sop_file_list.append(sop_file_obj)

            return(sop_file_list)
        except Exception as e:
            err_info = "Error occus in Consolidation::_getFileList(self, dbfile, file_type)"
            print(err_info)
            print(str(e))
            error.ErrorCurrentFeature(information=err_info, details=str(e))
        finally:
            print("End -> Consolidation::_getFileList(self, dbfile, file_type)")

    def _getAdditionalAttributes(self, dbfile):
        print("Consolidation::_getAdditionalAttributes(self, dbfile)")

        # Initialyze the return value.
        sop_attr_list = list()

        try:
            # Get image files related to the consolidation.
            sql_select = """SELECT uuid FROM additional_attribute WHERE ref_table = 'consolidation' AND ref_uuid=?;"""
            print(sql_select)
            # Execute the query.
            sop_attrs = super(Consolidation, self).fetchAllSQL(dbfile, sql_select, [self._uuid])

            # Exit if there are no entries.
            if (sop_attrs == None or len(sop_attrs) <= 0): return(sop_attr_list)

            # Create sop image ojects from the DB table.
            for sop_attr in sop_attrs:
                sop_attr_list.append(AdditionalAttribute(is_new=False, uuid=sop_attr[0], dbfile=dbfile, ref_table="consolidation", ref_uuid=self._uuid))

            return(sop_attr_list)
        except Exception as e:
            err_info = "Error occus in Consolidation::_getAdditionalAttributes(self, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

class Material(SimpleObject):
    @property
    def consolidation(self): return self._consolidation
    @property
    def name(self): return self._name
    @property
    def estimated_period_beginning(self): return self._estimated_period_beginning
    @property
    def estimated_period_peak(self): return self._estimated_period_peak
    @property
    def estimated_period_ending(self): return self._estimated_period_ending
    @property
    def latitude(self): return self._latitude
    @property
    def longitude(self): return self._longitude
    @property
    def altitude(self): return self._altitude
    @property
    def material_number(self): return self._material_number
    @property
    def images(self): return self._images
    @property
    def sounds(self): return self._sounds
    @property
    def movies(self): return self._movies
    @property
    def texts(self): return self._texts
    @property
    def geometries(self): return self._geometries
    @property
    def additionalAttributes(self): return self._additionalAttributes
    @property
    def description(self): return self._description

    @consolidation.setter
    def consolidation(self, value): self._consolidation = value
    @name.setter
    def name(self, value): self._name = value
    @estimated_period_beginning.setter
    def estimated_period_beginning(self, value): self._estimated_period_beginning = value
    @estimated_period_peak.setter
    def estimated_period_peak(self, value): self._estimated_period_peak = value
    @estimated_period_ending.setter
    def estimated_period_ending(self, value): self._estimated_period_ending = value
    @latitude.setter
    def latitude(self, value): self._latitude = value
    @longitude.setter
    def longitude(self, value): self._longitude = value
    @altitude.setter
    def altitude(self, value): self._altitude = value
    @material_number.setter
    def material_number(self, value): self._material_number = value
    @images.setter
    def images(self, value): self._images = value
    @sounds.setter
    def sounds(self, value): self._sounds = value
    @movies.setter
    def movies(self, value): self._movies = value
    @texts.setter
    def texts(self, value): self._texts = value
    @geometries.setter
    def geometries(self, value): self._geometries = value
    @additionalAttributes.setter
    def additionalAttributes(self, value): self._additionalAttributes = value
    @description.setter
    def description(self, value): self._description = value

    def __init__(self, is_new = True, uuid=None, dbfile=None):
        # Initialize the super class.
        SimpleObject.__init__(self, is_new, uuid, dbfile)

        if is_new == True and dbfile == None:
            # Initialize as the new instance.
            self._consolidation = None
            self._name = None
            self._estimated_period_beginning = None
            self._estimated_period_peak = None
            self._estimated_period_ending = None
            self._latitude = None
            self._longitude = None
            self._altitude = None
            self._material_number = None
            self._images = list()
            self._sounds = list()
            self._movies = list()
            self._texts = list()
            self._geometries = list()
            self._additionalAttributes = list()
            self._description = None
        elif is_new == False and uuid != None and dbfile != None:
            # Initialize by the DB instance.
            self._initInstanceByUuid(uuid, dbfile)
        else:
            # Other unexpected case.
            return(None)

    # operation
    def _initInstanceByUuid(self, uuid, dbfile):
        print("Start -> Material::_initInstanceByUuid(self, uuid, dbfile)")

        try:
            # Make the SQL statement.
            sql_select = """SELECT  id,
                                    con_id,
                                    name,
                                    material_number,
                                    estimated_period_beginning,
                                    estimated_period_peak,
                                    estimated_period_ending,
                                    latitude,
                                    longitude,
                                    altitude,
                                    material_number,
                                    description
                                FROM material WHERE uuid=?"""

            # Fech one from DB.
            print("## Fetch a Material: SimpleObject::fetchOneSQL")
            entry = super(Material, self).fetchOneSQL(dbfile, sql_select, [uuid])

            if not entry == None:
                # Get attributes from the row.
                self._id = entry[0]
                self._uuid = uuid
                self._consolidation = entry[1]
                self._name = entry[2]
                self._material_number = entry[3]
                self._estimated_period_beginning = entry[4]
                self._estimated_period_peak = entry[5]
                self._estimated_period_ending = entry[6]
                self._latitude = entry[7]
                self._longitude = entry[8]
                self._altitude = entry[9]
                self._material_number = entry[10]
                self._images = self._getFileList(dbfile, "image")
                self._sounds = self._getFileList(dbfile, "audio")
                self._movies = self._getFileList(dbfile, "movie")
                self._texts = self._getFileList(dbfile, "text")

                self._geometries = self._getFileList(dbfile, "geometry")
                self._additionalAttributes = self._getAdditionalAttributes(dbfile)
                self._description = entry[11]
            else:
                return(None)

        except Exception as e:
            err_info = "Error occus in Material::_initInstanceByUuid(self, uuid, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

        finally:
            print("End -> Material::_initInstanceByUuid(self, uuid, dbfile)")

    def dbInsert(self, dbfile):
        print("Material::dbInsert(self, dbfile)")

        try:
            # Insert a new record into the database
            values = [
                self._uuid,
                self._consolidation,
                self._name,
                self._material_number,
                self._estimated_period_beginning,
                self._estimated_period_peak,
                self._estimated_period_ending,
                self._latitude,
                self._longitude,
                self._altitude,
                self._description
            ]

            # Create the SQL query for inserting the new material.
            sql_insert = """INSERT INTO material (
                        uuid,
                        con_id,
                        name,
                        material_number,
                        estimated_period_beginning,
                        estimated_period_peak,
                        estimated_period_ending,
                        latitude,
                        longitude,
                        altitude,
                        description
                    ) VALUES (?,?,?,?,?,?,?,?,?,?,?)"""

            # Execute the query.
            super(Material, self).excuteSQL(dbfile, sql_insert, values)

            # Insert images of the Material.
            if not self._images == None:
                if len(self._images) <= 0:
                    for image in self._images: image.dbInsert(dbfile)

            # Insert sounds of the Material.
            if not self._sounds == None:
                if not len(self._sounds) <= 0:
                    for sound in self._sounds: sound.dbInsert(dbfile)

            # Insert movies of the Material.
            if not self._movies == None:
                if not len(self._movies) <= 0:
                    for movie in self._movies: movie.dbInsert(dbfile)

            # Insert texts of the Material.
            if not self._texts == None:
                if not len(self._texts) <= 0:
                    for text in self._texts: text.dbInsert(dbfile)

            # Insert geometry of the Consolidation.
            if not self._geometries == None:
                if not len(self._geometries) <= 0:
                    for geometry in self._geometries: geometry.dbInsert(dbfile)

            # Insert additional attributes.
            if not self._additionalAttributes == None:
                if not len(self._additionalAttributes) <= 0:
                    for additionalAttribute in self._additionalAttributes:
                        additionalAttribute.dbInsert(dbfile, "material", self._uuid)
        except Exception as e:
            err_info = "Error occus in Material::dbInsert(self, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

    def dbUpdate(self, dbfile):
        print("Material::dbUpdate(self, dbfile)")

        try:
            # Insert a new record into the database
            values = [
                self._name,
                self._material_number,
                self._estimated_period_beginning,
                self._estimated_period_peak,
                self._estimated_period_ending,
                self._latitude,
                self._longitude,
                self._altitude,
                self._description,
                self._uuid
            ]

            # Create the SQL query for updating the new material.
            sql_update = """UPDATE material
                        SET
                            name = ?,
                            material_number = ?,
                            estimated_period_beginning = ?,
                            estimated_period_peak = ?,
                            estimated_period_ending = ?,
                            latitude = ?,
                            longitude = ?,
                            altitude = ?,
                            description = ?
                        WHERE uuid = ?"""

            # Execute the query.
            super(Material, self).excuteSQL(dbfile, sql_update, values)

            if not self._images == None:
                if len(self._images) <= 0:
                    for image in self._images: image.dbUpdate(dbfile)

            # Insert sounds of the Material.
            if not self._sounds == None:
                if not len(self._sounds) <= 0:
                    for sound in self._sounds: sound.dbUpdate(dbfile)

            # Update sounds of the Consolidation.
            if not self._movies == None:
                if not len(self._movies) <= 0:
                    for movie in self._movies: movie.dbUpdate(dbfile)

            # Insert texts of the Material.
            if not self._texts == None:
                if not len(self._texts) <= 0:
                    for text in self._texts: text.dbUpdate(dbfile)

            # Update geometry of the Material.
            if not self._geometries == None:
                if not len(self._geometries) <= 0:
                    for geometry in self._geometries: geometry.dbUpdate(dbfile)

            # Insert additional attributes.
            if not self._additionalAttributes == None:
                if not len(self._additionalAttributes) <= 0:
                    for additionalAttribute in self._additionalAttributes:
                        additionalAttribute.dbUpdate(dbfile)
        except Exception as e:
            err_info = "Error occus in Material::dbUpdate(self, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

    def dbDrop(self, dbfile):
        print("Material::dbDrop(self, dbfile)")

        try:
            # Dropt the exsiting entry from the DB.
            values = [self._uuid]

            # Create the SQL query for deleting the existing materials.
            sql_delete = """DELETE FROM material WHERE uuid = ?"""

            # Execute the query.
            super(Material, self).excuteSQL(dbfile, sql_delete, values)
        except Exception as e:
            err_info = "Error occus in Material::dbDrop(self, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

    def _getFileList(self, dbfile, file_type):
        print("Material::_getFileList(self, dbfile, file_type)")

        # Initialyze the return value.
        sop_file_list = list()

        try:
            sql_select = """SELECT uuid FROM file WHERE con_id = ? AND mat_id=? AND file_type=? ORDER BY id DESC;"""

            # Execute the query.
            sop_files = super(Material, self).fetchAllSQL(dbfile, sql_select, [self._consolidation, self._uuid, file_type])

            # Create sop image ojects from the DB table.
            for sop_file in sop_files:
                sop_file_list.append(File(is_new=False, uuid=sop_file[0], dbfile=dbfile))

            return(sop_file_list)
        except:
            print("Error in instantiating the File object.")

    def _getAdditionalAttributes(self, dbfile):
        print("Material::_getAdditionalAttributes(self, dbfile)")

        # Initialyze the return value.
        sop_attr_list = list()

        try:
            # Get image files related to the consolidation.
            sql_select = """SELECT uuid FROM additional_attribute WHERE ref_table = 'material' AND ref_uuid=? ORDER BY id;"""

            # Execute the query.
            sop_attrs = super(Material, self).fetchAllSQL(dbfile, sql_select, [self._uuid])

            # Create sop image ojects from the DB table.
            for sop_attr in sop_attrs:
                sop_attr_list.append(AdditionalAttribute(is_new=False, uuid=sop_attr[0], dbfile=dbfile, ref_table="material", ref_uuid=self._uuid))

            return(sop_attr_list)
        except Exception as e:
            print((str(e)))

class File(SimpleObject):
    def __init__(self, is_new, uuid, dbfile):
        SimpleObject.__init__(self, is_new, uuid, dbfile)

        if is_new == True and dbfile == None:
            self._consolidation = None
            self._material = None
            self._filename = None
            self._created_date = None
            self._modified_date = None
            self._file_type = None
            self._alias = None
            self._status = None
            self._public = None
            self._lock = None
            self._source = None
            self._operation = None
            self._operating_application = None
            self._caption = None
            self._description = None
            self._additionalAttributes = list()
        elif is_new == False and uuid != None and dbfile != None:
            # Initialize by the DB instance.
            self._initInstanceByUuid(uuid, dbfile)

    @property
    def material(self): return self._material
    @property
    def consolidation(self): return self._consolidation
    @property
    def filename(self): return self._filename
    @property
    def created_date(self): return self._created_date
    @property
    def modified_date(self): return self._modified_date
    @property
    def file_type(self): return self._file_type
    @property
    def alias(self): return self._alias
    @property
    def status(self): return self._status
    @property
    def public(self): return self._public
    @property
    def lock(self): return self._lock
    @property
    def source(self): return self._source
    @property
    def operation(self): return self._operation
    @property
    def operating_application(self): return self._operating_application
    @property
    def caption(self): return self._caption
    @property
    def additionalAttributes(self): return self._additionalAttributes
    @property
    def description(self): return self._description

    @material.setter
    def material(self, value): self._material = value
    @consolidation.setter
    def consolidation(self, value): self._consolidation = value
    @filename.setter
    def filename(self, value): self._filename = value
    @created_date.setter
    def created_date(self, value): self._created_date = value
    @modified_date.setter
    def modified_date(self, value): self._modified_date = value
    @file_type.setter
    def file_type(self, value): self._file_type = value
    @alias.setter
    def alias(self, value): self._alias = value
    @status.setter
    def status(self, value): self._status = value
    @public.setter
    def public(self, value): self._public = value
    @lock.setter
    def lock(self, value): self._lock = value
    @source.setter
    def source(self, value): self._source = value
    @source.setter
    def source(self, value): self._source = value
    @operation.setter
    def operation(self, value): self._operation = value
    @operating_application.setter
    def operating_application(self, value): self._operating_application = value
    @caption.setter
    def caption(self, value): self._caption = value
    @additionalAttributes.setter
    def additionalAttributes(self, value): self._additionalAttributes = value
    @description.setter
    def description(self, value): self._description = value

    # operation
    def _initInstanceByUuid(self, uuid, dbfile):
        print("Start -> features::File::_initInstanceByUuid(self, " + uuid + ", dbfile)")

        try:
            # Make the SQL statement.
            sql_select = """SELECT
                                id,
                                con_id,
                                mat_id,
                                created_date,
                                modified_date,
                                file_name,
                                file_type,
                                make_public,
                                alias_name,
                                status,
                                is_locked,
                                source,
                                file_operation,
                                operating_application,
                                caption,
                                description
                            FROM file WHERE uuid=?"""

            # Fech one from DB.
            entry = super(File, self).fetchOneSQL(dbfile, sql_select, [str(uuid)])

            if not entry == None:
                # Get attributes from the row.
                self._id = str(entry[0])
                self._uuid = str(uuid)
                self._consolidation = str(entry[1])
                self._material = str(entry[2])
                self._created_date = str(entry[3])
                self._modified_date = str(entry[4])
                self._filename = str(entry[5])
                self._file_type = str(entry[6])
                self._public = str(entry[7])
                self._alias = str(entry[8])
                self._status = str(entry[9])
                self._lock = str(entry[10])
                self._source = str(entry[11])
                self._operation = str(entry[12])
                self._operating_application = str(entry[13])
                self._caption = str(entry[14])
                self._description = str(entry[15])
                self._additionalAttributes = self._getAdditionalAttributes(dbfile)
                for attr in self._additionalAttributes:
                    print(attr.uuid)
            else:
                return(None)
        except Exception as e:
            err_info = "Error occus in Material::dbInsert(self, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))
        finally:
            print("End -> features::File::_initInstanceByUuid")

    def dbInsert(self, dbfile):
        print(("features::File::dbInsert(self, " + dbfile + ")"))

        # Insert a new record into the database
        values = [
            self._uuid,
            self._consolidation,
            self._material,
            self._created_date,
            self._modified_date,
            self._filename,
            self._file_type,
            self._public,
            self._alias,
            self._status,
            self._lock,
            self._source,
            self._operation,
            self._operating_application,
            self._caption,
            self._description
        ]

        # Create the SQL query for updating the new consolidation.
        sql_insert = """INSERT INTO file (
                        uuid,
                        con_id,
                        mat_id,
                        created_date,
                        modified_date,
                        file_name,
                        file_type,
                        make_public,
                        alias_name,
                        status,
                        is_locked,
                        source,
                        file_operation,
                        operating_application,
                        caption,
                        description
                    ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"""

        # Execute the query.
        super(File, self).excuteSQL(dbfile, sql_insert, values)

        # Insert additional attributes.
        if not self._additionalAttributes == None:
            if not len(self._additionalAttributes) <= 0:
                for additionalAttribute in self._additionalAttributes:
                    additionalAttribute.dbInsert(dbfile, "file", self._uuid)

    def dbUpdate(self, dbfile):
        print("File::dbUpdate()")

        # Insert a new record into the database
        values = [
            self._consolidation,
            self._material,
            self._created_date,
            self._modified_date,
            self._filename,
            self._file_type,
            self._public,
            self._alias,
            self._status,
            self._lock,
            self._source,
            self._operation,
            self._operating_application,
            self._caption,
            self._description,
            self._uuid
        ]

        # Create the SQL query for updating the new consolidation.
        sql_update = """UPDATE file
                    SET
                        con_id = ?,
                        mat_id = ?,
                        created_date = ?,
                        modified_date = ?,
                        file_name = ?,
                        file_type = ?,
                        make_public = ?,
                        alias_name = ?,
                        status = ?,
                        is_locked = ?,
                        source = ?,
                        file_operation = ?,
                        operating_application = ?,
                        caption = ?,
                        description = ?
                    WHERE uuid = ?"""

        # Execute the query.
        super(File, self).excuteSQL(dbfile, sql_update, values)

    def writeAsXml(self):
        print("features::File::writeAsXml(self)")

        try:
            xml_root = et.Element('File')
            xml_root.set("id", self._id)
            xml_root.set("uuid", self._uuid)

            xml_consolidation = et.SubElement(xml_root, "consolidation")
            xml_consolidation.set("idref", self._consolidation)

            xml_material = et.SubElement(xml_root, "material")
            xml_material.set("idref", self._material)

            xml_created = et.SubElement(xml_root, 'created')
            xml_created.text = self._created_date

            xml_created = et.SubElement(xml_root, 'modifed')
            xml_created.text = self.modified_date

            xml_filename = et.SubElement(xml_root, 'filename')
            xml_filename.text = os.path.basename(self._filename)

            xml_filename = et.SubElement(xml_root, 'filetype')
            xml_filename.text = os.path.basename(self._file_type)

            xml_alias = et.SubElement(xml_root, 'alias')
            xml_alias.text = os.path.basename(self._alias)

            xml_caption = et.SubElement(xml_root, 'caption')
            xml_caption.text = os.path.basename(self._caption)

            xml_caption = et.SubElement(xml_root, 'description')
            xml_caption.text = os.path.basename(self._description)

            return(et.tostring(xml_root, pretty_print=True, xml_declaration=True))
        except:
            print("Error occured in XML output.")
            return(None)

    def _getAdditionalAttributes(self, dbfile):
        print("File::_getAdditionalAttributes(self, dbfile)")

        # Initialyze the return value.
        sop_attr_list = list()

        try:
            # Get image files related to the consolidation.
            sql_select = """SELECT uuid FROM additional_attribute WHERE ref_table = 'file' AND ref_uuid=?;"""
            print(sql_select)
            # Execute the query.
            sop_attrs = super(File, self).fetchAllSQL(dbfile, sql_select, [self._uuid])

            # Exit if there are no entries.
            if (sop_attrs == None or len(sop_attrs) <= 0): return(sop_attr_list)

            # Create sop image ojects from the DB table.
            for sop_attr in sop_attrs:
                sop_attr_list.append(AdditionalAttribute(is_new=False, uuid=sop_attr[0], dbfile=dbfile, ref_table="file", ref_uuid=self._uuid))

            return(sop_attr_list)
        except Exception as e:
            err_info = "Error occus in File::_getAdditionalAttributes(self, dbfile)"
            print(err_info)
            print((str(e)))
            error.ErrorCurrentFeature(information=err_info, details=str(e))

class AdditionalAttribute(SimpleObject):
    @property
    def key(self): return self._key
    @property
    def value(self): return self._value
    @property
    def datatype(self): return self._datatype
    @property
    def description(self): return self._description

    @key.setter
    def key(self, value): self._key = value
    @value.setter
    def value(self, value): self._value = value
    @datatype.setter
    def datatype(self, value): self._datatype = value
    @description.setter
    def description(self, value): self._description = value

    def __init__(self, is_new , uuid, dbfile, ref_table, ref_uuid):
        # Initialize the super class.
        SimpleObject.__init__(self, is_new=is_new, uuid=uuid, dbfile=dbfile)

        if is_new == True and dbfile == None:
            # Initialize as the new instance.
            self._key = None
            self._value = None
            self._datatype = None
            self._description = None
        elif is_new == False and uuid != None and dbfile != None and ref_table != None and ref_uuid != None:
            # Initialize by the DB instance.
            self._uuid = uuid
            self._initInstanceByUuid(ref_table, ref_uuid, dbfile)
        else:
            # Other unexpected case.
            print("Not Instantiated!!")
            return(None)

    # operation
    def _initInstanceByUuid(self, ref_table, ref_uuid, dbfile):
        print("AdditionalAttribute::_initInstanceByUuid(self, table, uuid, dbfile)")

        # Make the SQL statement.
        sql_select = """SELECT  uuid,
                                id,
                                key,
                                value,
                                datatype,
                                description
                            FROM additional_attribute WHERE ref_table=? AND ref_uuid=? AND uuid=?"""

        # Fech one from DB.
        entry = super(AdditionalAttribute, self).fetchOneSQL(dbfile, sql_select, [ref_table, ref_uuid, self._uuid])

        if not entry == None:
            # Get attributes from the row.
            self._uuid = entry[0]
            self._id = entry[1]
            self._key = entry[2]
            self._value = entry[3]
            self._datatype = entry[4]
            self._description = entry[5]
        else:
            return(None)

    def dbInsert(self, dbfile, ref_table, ref_uuid):
        print("AdditionalAttribute::dbInsert(self, dbfile, ref_table, ref_uuid)")

        # Insert a new record into the database
        values = [
            self._uuid,
            self._key,
            self._value,
            self._datatype,
            self._description,
            ref_table,
            ref_uuid
        ]

        # Create the SQL query for inserting the new consolidation.
        sql_insert = """INSERT INTO additional_attribute (
                    uuid,
                    key,
                    value,
                    datatype,
                    description,
                    ref_table,
                    ref_uuid
                ) VALUES (?,?,?,?,?,?,?)"""

        # Execute the query.
        super(AdditionalAttribute, self).excuteSQL(dbfile, sql_insert, values)

    def dbUpdate(self, dbfile):
        print("AdditionalAttribute::dbUpdate(self, dbfile)")

        # Insert a new record into the database
        values = [
            self._key,
            self._value,
            self._datatype,
            self._description,
            self._uuid
        ]

        # Create the SQL query for updating the new consolidation.
        sql_update = """UPDATE additional_attribute
                    SET
                        key = ?,
                        value = ?,
                        datatype = ?,
                        description = ?
                    WHERE uuid = ?"""
        print(values)
        # Execute the query.
        super(AdditionalAttribute, self).excuteSQL(dbfile, sql_update, values)

    def dbDrop(self, dbfile):
        print("AdditionalAttribute::dbDrop(self, dbfile)")

        # Dropt the exsiting entry from the DB.
        values = [self._uuid]

        # Create the SQL query for deleting the existing consolidation.
        sql_delete = """DELETE FROM additional_attribute WHERE uuid = ?"""

        # Execute the query.
        super(AdditionalAttribute, self).excuteSQL(dbfile, sql_delete, values)

def exportAsHtml(dbfile, output, title="Archive"):
    try:
        # Establish the connection between DB.
        conn = sqlite.connect(dbfile)

        if conn == None: return(None)

        # Open the file stream
        output_html = open(output,"w")

        output_html.write("<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<title>%s</title>\n\t</head>\t<body>\n\t\t<hr />\n" % (title))

        # Make the SQL statement.
        sql_sel_con = """SELECT uuid,
                                name,
                                geographic_annotation,
                                temporal_annotation,
                                description
                        FROM consolidation ORDER BY id;"""

        # Instantiate the cursor for query.
        cur_sel_con = conn.cursor()
        cur_sel_con.execute(sql_sel_con)

        # Fetch one row.
        con_rows = cur_sel_con.fetchall()

        # Replace NULL values by blank.
        for con_row in con_rows:
            con_uuid = con_row[0].encode('utf-8')
            con_cnam = con_row[1].encode('utf-8')
            con_gano = con_row[2].encode('utf-8')
            con_tano = con_row[3].encode('utf-8')
            con_desc = con_row[4].encode('utf-8')

            output_html.write("\t\t<div id='%s' style='text-align:center;'>\n" % (con_uuid))
            output_html.write("\t\t\t<table width='800' style='margin: auto; border: hidden; text-align: left'>\n\t\t\t\t<col width='200'>\n\t\t\t\t<col width='600'>\n")
            output_html.write("\t\t\t\t<tr><td colspan='2'><h1 style='text-align: center;'>%s</h1></td></tr>\n" % (con_cnam))
            output_html.write("\t\t\t\t<tr><td style='text-align: right; vertical-align: top'>Geographic Annotation :</td><td style='vertical-align: top'>%s</td></tr>\n" % (con_gano))
            output_html.write("\t\t\t\t<tr><td style='text-align: right; vertical-align: top'>Temporal Annotation :</td><td style='vertical-align: top'>%s</td></tr>\n" % (con_tano))
            output_html.write("\t\t\t\t<tr><td style='text-align: right; vertical-align: top' height='50'>Description :</td><td style='vertical-align: top'>%s</td></tr>\n" % (con_desc))
            output_html.write("\t\t\t</table>\n")

            sql_sel_con_img = '''SELECT    uuid,
                                            created_date,
                                            modified_date,
                                            file_name,
                                            alias_name,
                                            status,
                                            source,
                                            file_operation,
                                            caption,
                                            description
                                FROM file WHERE con_id = ? AND mat_id="NULL" AND file_type=? ORDER BY id DESC;'''

            # Instantiate the cursor for query.
            cur_sel_con_img = conn.cursor()
            cur_sel_con_img.execute(sql_sel_con_img, [con_uuid, "image"])

            con_img_rows = cur_sel_con_img.fetchall()

            output_html.write("\t\t\t<table width='800' style='margin: auto; border: hidden; text-align: left'>\n")
            output_html.write("\t\t\t\t<col width='200'>\n\t\t\t\t<col width='150'>\n\t\t\t\t<col width='150'>\n\t\t\t\t<col width='150'>\n\t\t\t\t<col width='150'>\n")
            output_html.write("\t\t\t\t<tr><td colspan='4'><h1 style='text-align: center;'>%s</h1></td></tr>\n" % ("Images"))
            for con_img_row in con_img_rows:
                con_img_uuid = con_img_row[0].encode('utf-8')
                con_img_cdat = con_img_row[1].encode('utf-8')
                con_img_mdat = con_img_row[2].encode('utf-8')
                con_img_fnam = con_img_row[3].encode('utf-8')
                con_img_stts = con_img_row[4].encode('utf-8')
                con_img_srce = con_img_row[5].encode('utf-8')
                con_img_fope = con_img_row[6].encode('utf-8')
                con_img_capt = con_img_row[7].encode('utf-8')
                con_img_desc = con_img_row[8].encode('utf-8')

                img_ext = os.path.splitext(con_img_fnam)[1]

                if img_ext == ".jpeg" or img_ext == ".jpg":
                    output_html.write("\t\t\t\t<tr style='vertical-align: top'>")
                    output_html.write("<td><img src='%s' height='40'/>$s</td><td>%s</td><td>$s</td><td>$s</td>" % (con_img_fnam, con_img_capt, con_img_stts, con_img_srce, con_img_desc))
                    output_html.write("<td>$s</td></tr>\n")
            output_html.write("\t\t\t</table>\n")

            # Make the SQL statement.
            sql_sel_mat = """SELECT uuid,
                                    name,
                                    material_number,
                                    estimated_period_beginning,
                                    estimated_period_peak,
                                    estimated_period_ending,
                                    latitude,
                                    longitude,
                                    altitude,
                                    description
                                FROM material WHERE con_id=?"""

            # Instantiate the cursor for query.
            cur_sel_mat = conn.cursor()
            cur_sel_mat.execute(sql_sel_mat, [con_row[0]])

            # Fetch one row.
            mat_rows = cur_sel_mat.fetchall()

            for mat_row in mat_rows:
                output_html.write("\t\t\t<div id='%s' style='text-align:center;'>\n\t\t\t\t\n" % (mat_row[0].encode('utf-8')))
                output_html.write("\t\t\t<table width='800' style='margin: auto; border: hidden; text-align: left'>\n\t\t\t\t<col width='200'>\n\t\t\t\t<col width='600'>\n")
                output_html.write("\t\t\t\t\t<tr><td colspan='2'><h2 style='text-align: center;'>%s</h2></td></tr>\n" % (mat_row[1].encode('utf-8')))
                output_html.write("\t\t\t\t\t<tr><td style='text-align: right; vertical-align: top'>Material Number :</td><td style='vertical-align: top'>%s</td></tr>\n" % (mat_row[2].encode('utf-8')))
                output_html.write("\t\t\t\t\t<tr><td style='text-align: right; vertical-align: top'>Latitude :</td><td style='vertical-align: top'>%s</td></tr>\n" % (mat_row[6].encode('utf-8')))
                output_html.write("\t\t\t\t\t<tr><td style='text-align: right; vertical-align: top'>Longitude :</td><td style='vertical-align: top'>%s</td></tr>\n" % (mat_row[7].encode('utf-8')))
                output_html.write("\t\t\t\t\t<tr><td style='text-align: right; vertical-align: top'>Altitude :</td><td style='vertical-align: top'>%s</td></tr>\n" % (mat_row[8].encode('utf-8')))
                output_html.write("\t\t\t\t\t<tr><td style='text-align: right; vertical-align: top'>Begining :</td><td style='vertical-align: top'>%s</td></tr>\n" % (mat_row[3].encode('utf-8')))
                output_html.write("\t\t\t\t\t<tr><td style='text-align: right; vertical-align: top'>Peak :</td><td style='vertical-align: top'>%s</td></tr>\n" % (mat_row[4].encode('utf-8')))
                output_html.write("\t\t\t\t\t<tr><td style='text-align: right; vertical-align: top'>Ending :</td><td style='vertical-align: top'>%s</td></tr>\n" % (mat_row[5].encode('utf-8')))
                output_html.write("\t\t\t\t\t<tr><td style='text-align: right; vertical-align: top' height='50'>Description :</td><td style='vertical-align: top'>%s</td></tr>\n" % (mat_row[9].encode('utf-8')))
                output_html.write("\t\t\t\t</table>\n\t\t\t</div>\n")

            output_html.write("\t\t</div>\n\t\t<hr />\n")
        output_html.write("\t</body>\n</html>")

        output_html.close()
    except Exception as e:
        print(e)

def whatisthis(s):
    if isinstance(s, str):
        print("ordinary string")
    elif isinstance(s, str):
        print("unicode string")
    else:
        print("not a string")


from django.shortcuts import render,redirect
from ajoutProduitCatalogue.models import *
from templates.forms import *

# Create your views here.
def index(request):
    return render(request, "index.html")

def listeProduits(request):
    tous_les_produits = Produit.objects.all()

    contenu = {"Produits": tous_les_produits}

    return render(request, "listeProduits.html", contenu)

def ajoutProduit(request):

    if request.method == "POST":
        form = frmAjoutProduit(request.POST)
        if form.is_valid():
            nv_produit = Produit()
            nv_produit.nom = form.cleaned_data['nom']
            nv_produit.description = form.cleaned_data['description']
            nv_produit.prix = form.cleaned_data['prix']
            nv_produit.save()
            return redirect("afficher_produit")
        else:
            print("Erreur, le formulaire n'est pas valide")

    else:
        form = frmAjoutProduit()
    contenu ={"formulaire" : form}

    return render(request,"ajoutProduit.html", contenu)


from functools import partial
from itertools import cycle

import matplotlib.pyplot as plt

from PySide6.QtCore import Qt, Signal
from PySide6.QtGui import QCursor
from PySide6.QtWidgets import (
    QCheckBox, QDialog, QDialogButtonBox, QMenu, QVBoxLayout
)

from hexrdgui.constants import ViewType
from hexrdgui.line_picker_dialog import LinePickerDialog
from hexrdgui.markers import igor_marker
from hexrdgui.tree_views.base_dict_tree_item_model import (
    BaseTreeItemModel, BaseDictTreeItemModel, BaseDictTreeView
)
from hexrdgui.tree_views.tree_item import TreeItem
from hexrdgui.tree_views.value_column_delegate import ValueColumnDelegate

# Global constants
KEY_COL = BaseTreeItemModel.KEY_COL
X_COL = KEY_COL + 1
Y_COL = X_COL + 1

class GenericPicksTreeItemModel(BaseDictTreeItemModel):

    def __init__(self, dictionary, coords_type=ViewType.polar, parent=None):
        super().__init__(dictionary, parent)

        self.root_item = TreeItem([''] * 3)
        self.coords_type = coords_type

        self.rebuild_tree()

    @property
    def coords_type(self):
        return self._coords_type

    @coords_type.setter
    def coords_type(self, v):
        self._coords_type = v
        self.update_root_item()

    def update_root_item(self):
        options = {
            ViewType.raw: ['i', 'j'],
            ViewType.cartesian: ['x', 'y'],
            ViewType.polar: ['2θ', 'η'],
        }

        if self.coords_type not in options:
            raise NotImplementedError(self.coords_type)

        labels = options[self.coords_type]
        row = self.root_item.row()
        for i in range(2):
            col = i + 1
            self.root_item.set_data(col, labels[i])
            index = self.createIndex(row, col, self.root_item)
            self.dataChanged.emit(index, index)

    def recursive_add_tree_items(self, cur_config, cur_tree_item):
        def is_coords(x):
            return (
                isinstance(x, (tuple, list)) and
                len(x) == 2 and
                all(isinstance(y, (int, float)) for y in x)
            )

        if is_coords(cur_config):
            x, y = cur_config
            cur_tree_item.set_data(X_COL, x)
            cur_tree_item.set_data(Y_COL, y)
            return
        elif isinstance(cur_config, dict):
            keys = cur_config.keys()
        elif isinstance(cur_config, (list, tuple)):
            keys = range(len(cur_config))
        else:
            # This shouldn't happen
            raise Exception(f'Unknown item: {cur_config}')

        for key in keys:
            path = self.path_to_value(cur_tree_item, 0) + [key]
            if path in self.blacklisted_paths or str(key).startswith('_'):
                continue

            data = [key if isinstance(key, (str, int)) else '', None, None]
            tree_item = self.add_tree_item(data, cur_tree_item)
            self.recursive_add_tree_items(cur_config[key], tree_item)

    def path_to_value(self, tree_item, column):
        return self.path_to_item(tree_item) + [column - 1]

class GenericPicksTreeView(BaseDictTreeView):

    dict_modified = Signal()

    def __init__(self, dictionary, coords_type=ViewType.polar, canvas=None,
                 parent=None, model_class=GenericPicksTreeItemModel,
                 model_class_kwargs=None):
        super().__init__(parent)

        self.canvas = canvas
        self.allow_hand_picking = True
        self.all_picks_line_artists = []
        self.selected_picks_line_artists = []
        self.is_deleting_picks = False
        self._show_all_picks = True
        self.new_line_name_generator = None

        if model_class_kwargs is None:
            model_class_kwargs = {}

        self.setModel(model_class(dictionary, coords_type, self,
                                  **model_class_kwargs))

        value_cols = [X_COL, Y_COL]
        all_cols = [KEY_COL] + value_cols
        for col in value_cols:
            self.setItemDelegateForColumn(col, ValueColumnDelegate(self))

        for col in all_cols:
            self.resizeColumnToContents(col)
            self.header().resizeSection(col, 200)

        # Allow extended selection
        self.set_extended_selection_mode()
        self.expand_rows()

        self.setup_connections()

        self.draw_picks()

    def setup_connections(self):
        self.selection_changed.connect(self.selection_was_changed)
        self.model().dict_modified.connect(self.data_was_modified)

    def selection_was_changed(self):
        if self.is_deleting_picks:
            # Don't re-highlight and re-draw for every pick that is deleted
            return

        self.highlight_selected_lines()
        self.draw_picks()

    def highlight_selected_lines(self):
        # Do nothing by default
        pass

    def data_was_modified(self):
        self.draw_picks()
        self.dict_modified.emit()

    def delete_selected_picks(self):
        self.is_deleting_picks = True
        try:
            self._delete_selected_picks()
        finally:
            self.is_deleting_picks = False

        self.selection_was_changed()

    def _delete_selected_picks(self):
        model = self.model()
        items_to_remove = []
        for item in self.selected_items:
            # These rows will actually be removed
            items_to_remove.append(item)

        if items_to_remove:
            model.remove_items(items_to_remove)
            self.draw_picks()

    @property
    def show_all_picks(self):
        return self._show_all_picks

    @show_all_picks.setter
    def show_all_picks(self, b):
        if self.show_all_picks == b:
            return

        self._show_all_picks = b
        self.draw_picks()

    def set_show_all_picks(self, b):
        self.show_all_picks = b

    def draw_picks(self):
        self.clear_artists()
        if not self.canvas:
            return

        self.draw_all_picks()
        self.draw_selected_picks()

    @property
    def all_pick_items(self):
        # Take self.all_pick_items_grouped and flatten them out
        items = []
        for group in self.all_pick_items_grouped.values():
            items.extend(group)
        return items

    @property
    def all_pick_items_grouped(self):
        # Recurse through all items and pull out all pick items
        # We assume an item is a pick item if it is not the root, and
        # it doesn't contain any None values.
        # These items will be grouped by parent.
        items = {}

        def recurse(parent):
            group = []
            for child in parent.child_items:
                if not any(x is None for x in child.data_list):
                    group.append(child)

                recurse(child)

            if group:
                items[parent] = group

        recurse(self.model().root_item)
        return items

    @property
    def selected_items_grouped(self):
        selected_items = self.selected_items
        if not selected_items:
            # Return early
            return {}

        # Use all the same keys as all_pick_items_grouped so that the colors
        # from the cycler match up.
        selected_grouped = {key: [] for key in self.all_pick_items_grouped}
        for item in selected_items:
            selected_grouped[item.parent_item].append(item)

        return selected_grouped

    @property
    def default_line_settings(self):
        return {
            'marker': igor_marker,
            'markeredgecolor': 'black',
            'markersize': 16,
            'linestyle': 'None',
        }

    @property
    def highlighted_line_settings(self):
        return {
            'marker': igor_marker,
            'markeredgecolor': 'yellow',
            'markersize': 16,
            'linestyle': 'None',
        }

    def create_color_cycler(self):
        prop_cycle = plt.rcParams['axes.prop_cycle']
        return cycle(prop_cycle.by_key()['color'])

    def draw_all_picks(self):
        if not self.show_all_picks:
            return

        line_settings = self.default_line_settings
        color_cycler = self.create_color_cycler()

        for group in self.all_pick_items_grouped.values():
            line_settings['color'] = next(color_cycler)

            xys = [item.data_list[1:] for item in group]
            artist, = self.canvas.axis.plot(*list(zip(*xys)), **line_settings)
            self.all_picks_line_artists.append(artist)

        self.canvas.draw_idle()

    def draw_selected_picks(self):
        if not self.selected_items:
            return

        line_settings = self.default_line_settings
        if self.show_all_picks:
            # Use highlighted line settings instead
            line_settings = self.highlighted_line_settings

        color_cycler = self.create_color_cycler()

        for group in self.selected_items_grouped.values():
            # Always cycle to the next color, even if the group is empty,
            # so that the colors will match up with all_pick_items_grouped
            line_settings['color'] = next(color_cycler)

            if not group:
                continue

            xys = [item.data_list[1:] for item in group]
            artist, = self.canvas.axis.plot(*list(zip(*xys)), **line_settings)
            self.selected_picks_line_artists.append(artist)

        self.canvas.draw_idle()

    def clear_artists(self):
        while self.all_picks_line_artists:
            self.all_picks_line_artists.pop(0).remove()

        while self.selected_picks_line_artists:
            self.selected_picks_line_artists.pop(0).remove()

        self.canvas.draw_idle()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Delete:
            self.delete_selected_picks()
        return super().keyPressEvent(event)

    def contextMenuEvent(self, event):
        actions = {}

        index = self.indexAt(event.pos())
        model = self.model()
        item = model.get_item(index)
        path = model.path_to_item(item)
        line_name_clicked = len(path) == 1
        point_clicked = len(path) == 2
        line_name = str(path[0])
        selected_items = self.selected_items
        num_selected = len(selected_items)
        is_hand_pickable = self.is_hand_pickable

        menu = QMenu(self)

        # Helper functions
        def add_actions(d: dict):
            actions.update({menu.addAction(k): v for k, v in d.items()})

        def add_separator():
            if not actions:
                return
            menu.addSeparator()

        # Context menu methods
        def insert_item():
            if line_name_clicked:
                position = 0
                parent_item = item
            elif point_clicked:
                position = path[-1]
                parent_item = item.parent_item
            else:
                raise NotImplementedError

            new_item = TreeItem([position, 0., 0.])
            model.insert_items([new_item], parent_item, position)

            # Select the new item
            index = model.createIndex(new_item.row(), 0, new_item)
            self.setCurrentIndex(index)

            if is_hand_pickable:
                # Go ahead and get the user to hand pick the point...
                self.hand_pick_point(new_item, line_name)

        def hand_pick_item():
            self.hand_pick_point(item, line_name)

        # Action logic
        if line_name_clicked and self.can_add_lines:
            add_actions({'Append new line': self.append_new_line})

        add_actions({'Insert': insert_item})

        if is_hand_pickable and point_clicked:
            add_actions({'Hand pick': hand_pick_item})

        if num_selected > 0:
            add_actions({'Delete': self.delete_selected_picks})

        if not actions:
            # No context menu
            return

        # Open up the context menu
        action_chosen = menu.exec(QCursor.pos())

        if action_chosen is None:
            # No action chosen
            return

        # Run the function for the action that was chosen
        actions[action_chosen]()

    @property
    def has_canvas(self):
        return self.canvas is not None

    @property
    def is_hand_pickable(self):
        return self.allow_hand_picking and self.has_canvas

    @property
    def can_add_lines(self):
        return self.new_line_name_generator and self.has_canvas

    def hand_pick_point(self, item, pick_label=''):
        kwargs = {
            'canvas': self.canvas,
            'parent': self,
            'single_pick_mode': True,
        }

        picker = LinePickerDialog(**kwargs)
        picker.current_pick_label = pick_label
        picker.ui.setWindowTitle(pick_label)
        picker.start()

        finished_func = partial(self.point_picked, item=item)
        picker.point_picked.connect(finished_func)

    def point_picked(self, x, y, item):
        model = self.model()
        left = model.createIndex(item.row(), 1, item)
        right = model.createIndex(item.row(), 2, item)

        model.setData(left, x)
        model.setData(right, y)

        # Flag it as changed
        model.dataChanged.emit(left, right)

    def append_new_line(self):
        name = self.new_line_name_generator()
        config = self.model().config

        if name in config:
            msg = f'name {name} already exists in config! {list(config)}'
            raise Exception(msg)

        pick_label = f'Picking points for: {name}'
        kwargs = {
            'canvas': self.canvas,
            'parent': self,
        }

        picker = LinePickerDialog(**kwargs)
        picker.current_pick_label = pick_label
        picker.ui.setWindowTitle(pick_label)
        picker.ui.view_picks.setVisible(False)
        picker.start()

        def on_line_completed():
            # Just accept it
            picker.ui.accept()

        accepted_func = partial(self.finished_appending_new_line,
                                name=name, picker=picker)
        picker.accepted.connect(accepted_func)
        picker.line_completed.connect(on_line_completed)

    def finished_appending_new_line(self, name, picker):
        new_line = picker.line_data[0]
        self.model().config[name] = new_line.tolist()
        self.model().rebuild_tree()
        self.draw_picks()
        self.expand_rows()

    @property
    def coords_type(self):
        return self.model().coords_type

    @coords_type.setter
    def coords_type(self, v):
        self.model().coords_type = v

class GenericPicksTreeViewDialog(QDialog):

    dict_modified = Signal()

    def __init__(self, dictionary, coords_type=ViewType.polar, canvas=None,
                 parent=None):
        super().__init__(parent)

        self.setWindowTitle('Edit Picks')

        self.setLayout(QVBoxLayout(self))

        self.tree_view = GenericPicksTreeView(dictionary, coords_type, canvas,
                                              self)
        self.layout().addWidget(self.tree_view)

        # Add a checkbox for showing all
        cb = QCheckBox('Show all picks', self)
        cb.setChecked(self.tree_view.show_all_picks)
        cb.toggled.connect(self.tree_view.set_show_all_picks)
        self.layout().addWidget(cb)

        # Add a button box for accept/cancel
        buttons = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        self.button_box = QDialogButtonBox(buttons, self)
        self.layout().addWidget(self.button_box)

        self.resize(500, 500)

        self.setup_connections()

    def setup_connections(self):
        self.tree_view.dict_modified.connect(self.dict_modified.emit)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)
        self.finished.connect(self.on_finished)

    def on_finished(self):
        self.tree_view.clear_artists()


import re

import pytest
from django.contrib.gis.geos import Point

from care.facility.models import District, Facility, FacilityCapacity, FacilityLocalGovtBody, State
from care.users.models import User
from config.tests.helper import assert_equal_dicts, mock_equal

# flake8: noqa

@pytest.fixture()
def user_data():
    return dict(
        username="bar",
        user_type=5,
        district_id=13,
        phone_number="8887776664",
        gender=1,
        age=30,
        email="bar@foobar.com",
    )

@pytest.fixture()
def facility():
    f = Facility.objects.create(
        name="Foo",
        district=District(id=13, name="Kannur", state=State(id=1, name="Kerala")),
        facility_type=1,
        address="8/88, 1st Cross, 1st Main, Boo Layout",
        location=Point(24.452545, 49.878248),
        oxygen_capacity=10,
        phone_number="9998887776",
    )
    FacilityLocalGovtBody.objects.create(facility=f, local_body=None, district_id=13)
    return f

@pytest.mark.usefixtures("district_data")
@pytest.mark.django_db(transaction=True)
class TestFacility:
    def test_login_required(self, client):
        response = client.post("/api/v1/facility/", {},)
        assert response.status_code == 403

    def test_create(self, client, user, facility_data):
        client.force_authenticate(user=user)
        response = client.post("/api/v1/facility/", facility_data,)

        assert response.status_code == 201

        assert assert_equal_dicts(
            response.json(),
            {
                **facility_data,
                "id": mock_equal,
                "facility_type": "Educational Inst",
                "local_body": None,
                "local_body_object": None,
                "district": facility_data["district"],
                "district_object": {"id": facility_data["district"], "name": "Kannur", "state": mock_equal},
                "state": mock_equal,
                "state_object": {"id": mock_equal, "name": "Kerala"},
                "created_date": mock_equal,
                "modified_date": mock_equal,
            },
        )

        facility = Facility.objects.get(
            name=facility_data["name"],
            district=facility_data["district"],
            facility_type=facility_data["facility_type"],
            address=facility_data["address"],
            oxygen_capacity=facility_data["oxygen_capacity"],
            phone_number=facility_data["phone_number"],
            created_by=user,
        )
        assert facility
        assert facility.location.tuple == (
            facility_data["location"]["longitude"],
            facility_data["location"]["latitude"],
        )

    def test_active_check(self, client, user, facility):
        client.force_authenticate(user=user)
        facility.created_by = user
        facility.is_active = False
        facility.save()
        response = client.get(f"/api/v1/facility/{facility.id}/")
        assert response.status_code == 404

    def test_retrieve(self, client, user, facility):
        client.force_authenticate(user=user)
        facility.created_by = user
        facility.save()
        response = client.get(f"/api/v1/facility/{facility.id}/")
        assert response.status_code == 200

        assert response.json() == {
            "id": facility.id,
            "name": facility.name,
            "facility_type": "Educational Inst",
            "address": facility.address,
            "location": {"latitude": facility.location.tuple[1], "longitude": facility.location.tuple[0],},
            "local_body": None,
            "local_body_object": None,
            "district": 13,
            "district_object": {"id": 13, "name": "Kannur", "state": 1},
            "state": mock_equal,
            "state_object": {"id": mock_equal, "name": "Kerala"},
            "oxygen_capacity": facility.oxygen_capacity,
            "phone_number": facility.phone_number,
            "created_date": mock_equal,
            "modified_date": mock_equal,
        }

    def test_update(self, client, user, facility):
        client.force_authenticate(user=user)
        facility.created_by = user
        facility.save()

        new_district = {"id": 12, "name": "Wayanad"}

        response = client.put(
            f"/api/v1/facility/{facility.id}/",
            {
                "name": "Another name",
                "district": new_district["id"],
                "facility_type": facility.facility_type,
                "address": facility.address,
            },
        )
        assert response.status_code == 200
        assert response.json() == {
            "id": facility.id,
            "name": "Another name",
            "facility_type": "Educational Inst",
            "address": facility.address,
            "location": {"latitude": facility.location.tuple[1], "longitude": facility.location.tuple[0],},
            "local_body": None,
            "local_body_object": None,
            "district": new_district["id"],
            "district_object": {"id": new_district["id"], "name": new_district["name"], "state": 1},
            "state": mock_equal,
            "state_object": {"id": mock_equal, "name": "Kerala"},
            "oxygen_capacity": facility.oxygen_capacity,
            "phone_number": facility.phone_number,
            "created_date": mock_equal,
            "modified_date": mock_equal,
        }
        facility.refresh_from_db()
        assert facility.name == "Another name"

    def test_update_doesnt_change_creator(self, client, user, user_data, facility, facility_data):
        facility.created_by = User.objects.create(**user_data)
        facility.save()
        original_creator = facility.created_by

        user.is_superuser = True
        user.save()
        client.force_authenticate(user=user)

        response = client.put(f"/api/v1/facility/{facility.id}/", facility_data)
        assert response.status_code == 200
        facility.refresh_from_db()
        assert facility.created_by == original_creator

    def test_destroy(self, client, user, facility):
        client.force_authenticate(user=user)
        facility.created_by = user
        facility.save()

        response = client.delete(f"/api/v1/facility/{facility.id}/",)
        assert response.status_code == 403

        user.is_superuser = True
        user.save()
        response = client.delete(f"/api/v1/facility/{facility.id}/",)
        assert response.status_code == 204
        with pytest.raises(Facility.DoesNotExist):
            Facility.objects.get(id=facility.id)

    def test_list(self, client, user, facility):
        client.force_authenticate(user=user)
        facility.created_by = user
        facility.save()
        response = client.get(f"/api/v1/facility/")
        assert response.status_code == 200
        assert response.json() == {
            "count": 1,
            "next": None,
            "previous": None,
            "results": [
                {
                    "id": facility.id,
                    "name": facility.name,
                    "facility_type": "Educational Inst",
                    "address": facility.address,
                    "location": {"latitude": facility.location.tuple[1], "longitude": facility.location.tuple[0],},
                    "local_body": None,
                    "local_body_object": None,
                    "district": facility.district.id,
                    "district_object": {
                        "id": facility.district.id,
                        "name": facility.district.name,
                        "state": facility.district.state.id,
                    },
                    "state": facility.state.id,
                    "state_object": {"id": facility.state.id, "name": facility.state.name},
                    "oxygen_capacity": facility.oxygen_capacity,
                    "phone_number": facility.phone_number,
                    "created_date": mock_equal,
                    "modified_date": mock_equal,
                },
            ],
        }

    def test_list_all(self, client, user, facility):
        client.force_authenticate(user=user)
        response = client.get(f"/api/v1/facility/")
        assert response.status_code == 200
        assert response.json() == {"count": 0, "next": None, "previous": None, "results": []}

        response = client.get(f"/api/v1/facility/?all=true")
        assert response.json() == {
            "count": 1,
            "next": None,
            "previous": None,
            "results": [
                {
                    "id": facility.id,
                    "name": facility.name,
                    "facility_type": {"id": facility.facility_type, "name": "Educational Inst",},
                    "local_body": None,
                    "local_body_object": None,
                    "district": facility.district.id,
                    "district_object": {
                        "id": facility.district.id,
                        "name": facility.district.name,
                        "state": facility.district.state.id,
                    },
                    "state": facility.state.id,
                    "state_object": {"id": facility.state.id, "name": facility.state.name},
                },
            ],
        }

@pytest.mark.usefixtures("district_data")
@pytest.mark.django_db(transaction=True)
class TestFacilityBulkUpsert:
    def test_success(self, client, user, facility):
        capacity = FacilityCapacity.objects.create(
            facility=facility, room_type=1, total_capacity=50, current_capacity=0
        )
        facility.created_by = user
        facility.save()
        user.is_superuser = True
        user.save()
        client.force_authenticate(user=user)

        name = "Another"
        address = "Dasappan's House, Washington Jn, OolaMukk P.O."
        phone_number = "7776665554"
        response = client.post(
            "/api/v1/facility/bulk_upsert/",
            data=[
                {
                    "name": facility.name,
                    "district": facility.district.id,
                    "facility_type": 3,
                    "address": facility.address,
                    "capacity": [{"room_type": 1, "total_capacity": 100, "current_capacity": 48,}],
                },
                {
                    "name": name,
                    "district": 1,
                    "facility_type": 2,
                    "address": address,
                    "phone_number": phone_number,
                    "capacity": [
                        {"room_type": 0, "total_capacity": 350, "current_capacity": 150,},
                        {"room_type": 1, "total_capacity": 200, "current_capacity": 100,},
                    ],
                },
            ],
        )
        assert response.status_code == 204

        facility.refresh_from_db()
        assert facility.facility_type == 3
        capacities = facility.facilitycapacity_set.all()
        assert capacities[0].id == capacity.id
        assert capacities[0].room_type == 1
        assert capacities[0].total_capacity == 100
        assert capacities[0].current_capacity == 48
        assert len(capacities) == 1

        new_facility = Facility.objects.get(
            created_by=user, name=name, district_id=1, facility_type=2, address=address, phone_number=phone_number,
        )
        assert new_facility
        capacities = new_facility.facilitycapacity_set.all()
        assert capacities[0].room_type == 0
        assert capacities[0].total_capacity == 350
        assert capacities[0].current_capacity == 150
        assert capacities[1].room_type == 1
        assert capacities[1].total_capacity == 200
        assert capacities[1].current_capacity == 100
        assert len(capacities) == 2

    def test_super_user_access(self, client, user, facility):
        client.force_authenticate(user=user)
        response = client.get(f"/api/v1/facility/{facility.id}/")
        assert response.status_code == 404

        user.is_superuser = True
        user.save()
        response = client.get(f"/api/v1/facility/{facility.id}/")
        assert response.status_code == 200
        assert response.json() == {
            "id": facility.id,
            "name": facility.name,
            "facility_type": "Educational Inst",
            "address": facility.address,
            "location": {"latitude": facility.location.tuple[1], "longitude": facility.location.tuple[0],},
            "local_body": None,
            "local_body_object": None,
            "district": facility.district.id,
            "district_object": {
                "id": facility.district.id,
                "name": facility.district.name,
                "state": facility.district.state.id,
            },
            "state": facility.state.id,
            "state_object": {"id": facility.state.id, "name": facility.state.name},
            "oxygen_capacity": facility.oxygen_capacity,
            "phone_number": facility.phone_number,
            "created_date": mock_equal,
            "modified_date": mock_equal,
        }

    def test_others_cant_update_ones_facility(self, client, user, facility):
        client.force_authenticate(user=user)
        response = client.post(
            "/api/v1/facility/bulk_upsert/",
            data=[
                {
                    "name": facility.name,
                    "district": facility.district.id,
                    "facility_type": 3,
                    "address": facility.address,
                    "capacity": [{"room_type": 1, "total_capacity": 100, "current_capacity": 48,}],
                },
            ],
        )
        assert response.status_code == 403

    def test_admins_can_update_ones_facility(self, client, user, facility):
        client.force_authenticate(user=user)
        user.is_superuser = True
        user.save()
        response = client.post(
            "/api/v1/facility/bulk_upsert/",
            data=[
                {
                    "name": facility.name,
                    "district": facility.district.id,
                    "facility_type": 3,
                    "address": facility.address,
                    "capacity": [{"room_type": 1, "total_capacity": 100, "current_capacity": 48,}],
                },
            ],
        )
        assert response.status_code == 204


import configparser
import json

from flask import Flask, request, jsonify

from AccessManagementService import ServiceInterface, logging, databaseInstance, app

databaseInstance.init_app(app)
config = configparser.ConfigParser()
config.read('AccessManagementConfig.ini')

def request_preparation(request, path):
    temp = {}
    if request.method == 'GET':

        """ Extracting all the query parameters from the request"""
        parameters = {}
        for i in request.args.keys():
            parameters[i] = request.args.get(i)

        temp["param"] = parameters
        temp["task"] = path
    else:
        data = json.loads(str(request.data).replace("b", "", 1).replace("'", ""))
        temp["data"] = data
        temp["task"] = path
    return temp

@app.route('/<path:path>', methods=['POST', 'GET'])
def catch_all(path):
    transformed_request = request_preparation(request, path)
    logging.info("Transformed Request From Web %s", transformed_request)
    service = ServiceInterface.ServiceInterface(transformed_request)
    logging.info("Response  %s", service.result)
    return jsonify(service.result)

if __name__ == '__main__':
    Flask.run(app, port=5005)


import asyncio
import pyautogui
import time
from struct import unpack
from bleak import BleakClient

address = "61:D7:A3:07:2F:15"
characteristic_uuid = "19b10000-2905-537e-4f6c-d104768a1214"

async def main(address):
    async with BleakClient(address) as client:
        client.get_services()
        while True:
            data = await client.read_gatt_char(characteristic_uuid)
            x, y, z = unpack('fff', data)
            print(x,y,z)
            if x<-2500 and x<2500:
                pyautogui.press('right')
                print("right")
                #time.sleep(1)
            if x>2500 and x>-2500:
                pyautogui.press('left')
                print("left")
            '''if y<-2500 and y<2500:
                pyautogui.press('up')
                print("up")
                time.sleep(1)
            if y>2500 and y>-2500:
                pyautogui.press('down')
                print("down")'''
            if z>10000:
                print("Pause")
                pyautogui.press('s')

asyncio.run(main(address))