# -----------------------------------
# Imports des librairies
# -----------------------------------
try:
    from PIL import Image
    from uuid import uuid4
    import json
except ImportError:
    import Image
import pytesseract
from pytesseract import Output
import cv2
import sys
import re
from pdf2image import convert_from_path
from TSLibOCR import *
import time
import os
import numpy as np
from TS_OCR import *
import MySQLdb
from datetime import datetime
from collections import Counter

""" Retourne le temps passé depuis le lancement du programme """
def getTime():
    return ""


class Cooperl(TS_OCR):
    debug = False
    sqlUser = 'toosmart'
    sqlHost = ''
    sqlPasswd = 'i5Hf7MSHKkPN1hy'
    sqlDb = ''
    linesPoids = []
    linesLots = []
    lineMerged = {}
    dateLivraison = ""
    typeLivraison = ""
    enAnomalie = 0
    poidsTotal = 0.000
    cleCoche = "C[\w\S]*E COUPE EURO [EF]ILIERE LBC"
    ocrDpi = 170
    ocrFolder = '/home/serge/www/toosmart_digicoche/data/tmp/'
    outputFileName = ''
    motsASurligner = []
    dateTuerie = ""
    poidsTotalCalcule = 0.000
    poidsTotalDetecte = 0
    qttCocheCalcule = 0
    qttCocheDetecte = 0
    nonIntegrable = False
    idAbattoir = 26
    quantieme = 0


    def __init__(self, pdf, outputFileName,ocrDirectory,dbName,sqlHost,debug):
        try:
            self.debug = debug
            self.sqlDb = dbName
            self.sqlHost = sqlHost
            """ Connexion à la base de données MySQL de Digicoche (Eteko)"""
            self.conn = MySQLdb.connect(host=self.sqlHost, user=self.sqlUser, passwd=self.sqlPasswd, db=self.sqlDb)
            self.cursor = self.conn.cursor()
            self.pdf = pdf
            self.outputFileName = outputFileName
            self.ocrFolder = ocrDirectory

            self.printDebug("Connexion à la base de données OK")
            self.printDebug("outputFileName = " + str(outputFileName))

        except:
            self.printDebug("Erreur de connexion à la base de données")

    def printDebug(self,pTxt):
        self._debugOCR = self._debugOCR + '<br />' + pTxt
        if self.debug:
            print(pTxt)
            
    # Analyse du BL de l'abattoir Cooperl
    def read(self):
        try:
            # lecture
            pagesPdf = convert_from_path(self.pdf, self.ocrDpi)
            iPage = 1
            ocrReturnArray = []
            """ On parcours les pages du pdf  """
            for page in pagesPdf:
                try:
                    # conversion de l'image en fichier jpeg
                    image_name = "Page_" + str(iPage) + ".jpg"
                    page.save(self.ocrFolder + image_name, "JPEG")
                    # ---------------------------------

                    # Optimisation de l'image
                    img = cv2.imread(self.ocrFolder + image_name)
                    imageAmelioree = img.copy()
                    cv2.imwrite(self.ocrFolder + 'Page_' + str(iPage) + '_result.jpg', imageAmelioree)
                    imageAmelioreeSurlignee = Image.open(self.ocrFolder + 'Page_' + str(iPage) + '_result.jpg')
                    # ---------------------------------

                    # On lance la reconnaissance OCR sur l'image
                    df = pytesseract.image_to_string(np.array(imageAmelioree), lang='fra', config=' --oem 0 --psm 4')
                    ocrReturnArray.append(df)
                    # ---------------------------------

                    iPage = iPage + 1


                except Exception as err:
                    self.printDebug(f"Unexpected {err=}, {type(err)=}")
                    self.printDebug("ERROR")

            try:
                # Recherche du type de livraison
                m = re.search(self.cleCoche, ocrReturnArray[0])
                if m is not None:
                    self.typeLivraison = m.group()
                else:
                    # BL Non intégrable car la clef n'est pas correcte
                    # On retourne dans le bash l'information puis on quitte le script
                    # (NE PAS SUPPRIMER CETTE LIGNE !!!)
                    self.printDebug("------")
                    self.printDebug(ocrReturnArray[0])
                    self.printDebug("------")
                    self.printDebug("Le BL ne comporte pas la bonne clé coche : "+self.cleCoche)
                    print('{"blNonIntegrable":1}')
                    self.nonIntegrable = True
                    return False

            except Exception as err:
                self.printDebug(f"Unexpected {err=}, {type(err)=}")
                self.printDebug("ERROR")
            # ---------------------------------
            self.printDebug('1 : ' + ocrReturnArray[0])

            # Recherche du numéro du BL
            try:
                self.printDebug('1 : '+ocrReturnArray[0])

                m = re.findall(r"^([0-9]{6}) [\w]+$", ocrReturnArray[0], re.MULTILINE)
                if len(m) > 0:
                    for element in m:
                        self._numBl = element
                else:
                    m = re.findall(r"[A-Z]ON DE LIVRAISON[ ]?N°[\D]+([0-9]{6})", ocrReturnArray[0],re.MULTILINE | re.IGNORECASE)
                    if len(m) > 0:
                        for element in m:
                            self._numBl = element


            except Exception as err:
                self._numBl = ""
                self.printDebug(f"Unexpected1 {err=}, {type(err)=}")
                self.printDebug("ERROR1")

            if self._numBl != "":
                if self.blExist():
                    # Le BL Existe déjà en base de donneés
                    print('{"blEnDoublon":1}')
                    self.nonIntegrable = True
                    return False
            # ---------------------------------


            # Recherche de la date de livraison
            m = re.findall(r"Date livraison\s+((?:[0-9 ]\s*){1,3}\/\s*(?:[0-9 ]\s*){1,3}\/\s*(?:[0-9 ]\s*){2,3})", ocrReturnArray[0])
            if len(m) > 0:
                self.dateLivraison = str(m[0]).replace(' ','')
                self.motsASurligner.append(m[0])
            #else:
            #    m = re.findall(r"([0-9]{1,2}/[0-9]{1,2}/[0-9]{2})", ocrReturnArray[0])
            #    if len(m) > 0:
            #        self.dateLivraison = str(m[0])
            #        self.motsASurligner.append(m[0])

            # ---------------------------------

            # Recherche du poids total
            try:
                m = re.findall(r""+self.cleCoche+"\D+(([\d,])*)[| ]*(([\d,])*)", ocrReturnArray[0],re.MULTILINE)
                if len(m) > 0:
                    for element in m:
                        self.poidsTotalDetecte = element[2]
                        self.qttCocheDetecte = element[0]

            except Exception as err:
                self.printDebug(f"Unexpected 1 {err=}, {type(err)=}")
                self.printDebug("ERROR1")
            # ---------------------------------
            # On parcours les pages du BL pour rechercher les données
            for Sfile in ocrReturnArray:
                #print(Sfile)
                # Recherche du nombre de coches, du poids et du lot
                if self.typeLivraison != "": # On vérifie si le type de livraison du BL est bien autorisé
                    m = re.findall(r"([0-9]{1,3})[. ]{0,2}([0-9]{1,4}) ([0-9]{1,3}[.,][0-9]*)", Sfile)
                    if len(m) > 0:
                        self.linesPoids.extend(m)
                        self.qttCocheCalcule = len(m)

                        for poid in m:
                            # on ajoute le poids détecté au poids total
                            self.poidsTotal = round(self.poidsTotal + round(float(poid[2].replace(",", ".")), 3), 3)
                            self.quantieme = poid[0]

            # Gestion de l'image pour surlignage des zones
            tesseract_output = pytesseract.image_to_data(np.array(imageAmelioreeSurlignee),output_type=pytesseract.Output.DICT)

            try:
                self.surlignerZones(tesseract_output)
            except Exception as err:
                print(f"Unexpected 2 cooperl.py {err=}, {type(err)=}")
                print("ERROR2")
            # ---------------------------------
        except Exception as e:
            exception_type, exception_object, exception_traceback = sys.exc_info()
            filename = exception_traceback.tb_frame.f_code.co_filename
            line_number = exception_traceback.tb_lineno
            print("Exception type: ", exception_type)
            print("File name: ", filename)
            print("Line number: ", line_number)
            self.printDebug(f"Unexpected {e=}, {type(e)=}")
            self.printDebug("ERROR")

    """ Surligne les zones détectées par l'OCR dans le fichier """
    def surlignerZones(self, tesseract_output):
        try:
            imageASurligner = cv2.imread(self.ocrFolder + 'Page_1_result.jpg')
            blockASurligner = []
        except Exception as err:
            print(f"Unexpected C {err=}, {type(err)=}")
            print("ERRORC")

        try:
            for i, level_idx in enumerate(tesseract_output['level']):
                if level_idx == 5:
                    # if tesseract_output['text'][i] in self.motsASurligner:
                    bbox = {
                        'x': 1 * tesseract_output['left'][i],
                        'y': 1 * tesseract_output['top'][i],
                        'width': 1 * tesseract_output['width'][i],
                        'height': 1 * tesseract_output['height'][i],
                        'rotation': 0,
                        'confidence': tesseract_output['conf'][i],
                        'text': tesseract_output['text'][i]
                    }

                    if int(tesseract_output['conf'][i]) >= 85:
                        color = (42, 219, 151)
                    elif int(tesseract_output['conf'][i]) >= 50:
                        color = (0, 165, 255)
                    else:
                        color = (0, 0, 255)
                    try:
                        overlay = imageASurligner.copy()
                        cv2.rectangle(overlay, (bbox['x'], bbox['y']),
                                      (bbox['x'] + bbox['width'], bbox['y'] + bbox['height']), color, cv2.FILLED)
                        alpha = 0.5
                        imageASurligner = cv2.addWeighted(overlay, alpha, imageASurligner, 1 - alpha, 0)
                        blockASurligner.append(bbox)
                    except Exception as err:
                        print(f"UnexpectedD {err=}, {type(err)=}")
                        print("ERRORD")
        except Exception as err:
            print(f"Unexpected D {err=}, {type(err)=}")
            print("ERRORD")
        # On sauvegarde le fichier
        try:
            imageASurligner = cv2.cvtColor(imageASurligner, cv2.COLOR_BGR2RGB)
            img = Image.fromarray(imageASurligner, "RGB")
            img.save(self.ocrFolder+self.outputFileName+"-BL.pdf")
            #print('Save into : '+self.ocrFolder + 'BL.pdf')

        except Exception as err:
            print("erreur")
            print(f"UnexpectedE {err=}, {type(err)=}")

        return True


    def mergeData(self):
        try:
            if self.nonIntegrable:
                return False

            for linePoids in self.linesPoids:
                self.lineMerged[linePoids[1]] = {"poids" : linePoids[2], "quantieme" : linePoids[0],"lot":linePoids[1]}

            try:
                # On stocke la date de livraison dans le format YYYYMMDD
                self.dateLivraison = datetime.strptime(self.dateLivraison, "%d/%m/%y").strftime("%Y%m%d")
            except:
                self.dateLivraison = ""

            self.qttCocheCalcule = len(self.lineMerged)
            try:
                for key in self.lineMerged:
                    # on ajoute le poids détecté au poids total
                    self.poidsTotalCalcule = round(self.poidsTotalCalcule + round(float(self.lineMerged[key]["poids"].replace(",", ".")), 3), 3)
            except Exception as err:
                print(f"Unexpected {err=}, {type(err)=}")
                print("ERROR A1")


            # On créé l'entête du BL dans eteko


            # Date de création de la ligne
            currentDate = datetime.now().strftime('%Y%m%d%H%M')

            sql = "INSERT INTO tier_att(id_base, id_type, id_tier,attdatcre, id_work, actif, newobj, att1, att2, att3,att6,att7,att8,att9,attf100,att17,att90) VALUES (1, 10, NULL,'"+str(currentDate)+"', 16, 1, 0, "+str(self.idAbattoir)+", '" + self.typeLivraison + "', '" + str(
                self.poidsTotalCalcule) + "','" + str(self.poidsTotalDetecte) + "','" + str(
                self.poidsTotalCalcule) + "',ROUND('" + str(self.qttCocheDetecte) + "'),'" + str(
                self.qttCocheCalcule) + "', '" + self.dateLivraison + "','"+ self._numBl +"','"+ self._debugOCR.replace("'", "\\'") +"');"
            try:
                self.cursor.execute(sql)
            except Exception as err:
                print(f"Unexpected {err=}, {type(err)=}")
                print("ERROR A2 "+ sql)

            # On récupère l'id du BL créé dans Eteko
            blId = self.cursor.lastrowid

            # On retourne dans le bash l'id du BL créé
            # (NE PAS SUPPRIMER CETTE LIGNE !!!)
            print('{"blId":' + str(blId) + "}")
            # ------------------------------------------
            if self.quantieme == '':
                self.quantieme = 0
            for key in self.lineMerged:
                numeroTuerie = str(self.lineMerged[key]["lot"])[-4:]

                sql = ("INSERT INTO prod_att(id_base, id_type, id_prod, id_work, actif, newobj, fid_prod, type, name, revision, `desc`, att1, att2, att3, att4, attf100, attf101,att10,attf104) VALUES (1, 11, NULL, 11, 1, 0, null, null, null, null, null, '" + str(
                    blId) + "','', '" + str(numeroTuerie) + "', '" +
                       str(self.lineMerged[key]["poids"]) + "', '" + str(self.quantiemeVersDate(int(self.quantieme))) + "', '" + str(
                    self.enAnomalie) + "','" + str(self.quantieme) + "','" + self.dateLivraison + "');")

                try:
                    self.cursor.execute(sql)
                except Exception as err:
                    print(f"Unexpected {err=}, {type(err)=}")
                    print("ERROR A3 " + sql)
                    print(sql)

            self.conn.close()
        except Exception as e:
            exception_type, exception_object, exception_traceback = sys.exc_info()
            filename = exception_traceback.tb_frame.f_code.co_filename
            line_number = exception_traceback.tb_lineno

            print("Exception type: ", exception_type)
            print("File name: ", filename)
            print("Line number: ", line_number)
            self.printDebug(f"Unexpected {e=}, {type(e)=}")
            self.printDebug("ERROR")
            self.printDebug(sql) 

    def quantiemeVersDate(self,n):
        try:
            a = datetime.now().year

            """Donne la date d=[j,m,a] qui est le nième jour de l'année a"""
            if ((a%4==0 and a%100!=0) or a%400==0):
                # bissextile?
                jm = (0,31,60,91,121,152,182,213,244,274,305,335,366)
            else:
                jm = (0,31,59,90,120,151,181,212,243,273,304,334,365)

            for m in range(1,13):
                if jm[m]>=n:
                    #return str(n)+str(jm[m-1])+ str(m)+ str(a)
                    return str(a) + str("{:02d}".format(m)) + str("{:02d}".format(n-jm[m-1]))

        except Exception as e:
            exception_type, exception_object, exception_traceback = sys.exc_info()
            filename = exception_traceback.tb_frame.f_code.co_filename
            line_number = exception_traceback.tb_lineno
            print("Exception type: ", exception_type)
            print("File name: ", filename)
            print("Line number: ", line_number)
            print("n: ", n)
            self.printDebug(f"Unexpected {e=}, {type(e)=}")
            self.printDebug("ERROR")