# class for iANPR2 SDK
import cv2
import numpy as np
import ctypes
import json
import logging

__name__ = "iANPR2PY"
logger = logging.getLogger(__name__)

class iANPR2(object):
    def __init__(self, dllPath):
        self.lib = ctypes.CDLL(dllPath)        
        # Функции
        # bool iANPR2Version(char* outBuf, int sizeBuf);
        self.iANPR2Version = self.lib.iANPR2Version
        self.iANPR2Version.restype = ctypes.c_bool
        self.iANPR2Version.argtypes = (ctypes.c_char_p,ctypes.c_int,)
        # void* iANPR2Init(char* configFile, char*license, int* error);
        self.iANPR2Init = self.lib.iANPR2Init
        self.iANPR2Init.restype = ctypes.c_void_p
        self.iANPR2Init.argtypes = (ctypes.c_char_p,ctypes.c_char_p,ctypes.POINTER(ctypes.c_int),)
        # void iANPR2Release(iANPR2Object* object);
        self.iANPR2ReleaseP = self.lib.iANPR2ReleaseP
        self.iANPR2ReleaseP.restype = ctypes.c_bool
        self.iANPR2ReleaseP.argtypes = (ctypes.c_void_p,)
        # bool iANPR2SettingsJSON(iANPR2Object object, char* json);
        self.iANPR2SettingsJSON = self.lib.iANPR2SettingsJSON
        self.iANPR2SettingsJSON.restype = ctypes.c_bool
        self.iANPR2SettingsJSON.argtypes = (ctypes.c_void_p,ctypes.c_char_p,)
        # int anpr2AddImage(iANPR2Object object, const char* image_bytes, long size_image);
        self.anpr2AddImage = self.lib.anpr2AddImage
        self.anpr2AddImage.restype = ctypes.c_int
        self.anpr2AddImage.argtypes = (ctypes.c_void_p,ctypes.c_char_p,ctypes.c_long,)
        # int anpr2inferenceFirstStep(iANPR2Object object);
        self.anpr2inferenceFirstStep = self.lib.anpr2inferenceFirstStep
        self.anpr2inferenceFirstStep.restype = ctypes.c_int
        self.anpr2inferenceFirstStep.argtypes = (ctypes.c_void_p,)
        # int anpr2inferenceSecondStep(iANPR2Object object);
        self.anpr2inferenceSecondStep = self.lib.anpr2inferenceSecondStep
        self.anpr2inferenceSecondStep.restype  = ctypes.c_int
        self.anpr2inferenceSecondStep.argtypes  = (ctypes.c_void_p,)
        # int anpr2inference(iANPR2Object object);
        self.anpr2inference = self.lib.anpr2inference
        self.anpr2inference.restype  = ctypes.c_int
        self.anpr2inference.argtypes = (ctypes.c_void_p,)
        # int anpr2GetResultJSON(iANPR2Object object, char* outBuf, int sizeBuf);
        self.anpr2GetResultJSON = self.lib.anpr2GetResultJSON
        self.anpr2GetResultJSON.restype = ctypes.c_int
        self.anpr2GetResultJSON.argtypes = (ctypes.c_void_p,ctypes.c_char_p,ctypes.c_int,)
        # int anpr2GetAddResultJSON(iANPR2Object object, char* outBuf, int sizeBuf);
        self.anpr2GetAddResultJSON = self.lib.anpr2GetAddResultJSON
        self.anpr2GetAddResultJSON.restype = ctypes.c_int
        self.anpr2GetAddResultJSON.argtypes = (ctypes.c_void_p,ctypes.c_char_p,ctypes.c_int,)
        #int anpr2GetResultMemJSON(iANPR2Object object, char* outBuf, int sizeBuf);
        self.anpr2GetResultMemJSON = self.lib.anpr2GetResultMemJSON
        self.anpr2GetResultMemJSON.restype = ctypes.c_int
        self.anpr2GetResultMemJSON.argtypes = (ctypes.c_void_p,ctypes.c_char_p,ctypes.c_int,)
        #void* iANPR2Trajectory(int widthImage, int heightImage, int tLimitTime, int tLimitFrames, int typeSpeed);
        self.iANPR2Trajectory = self.lib.iANPR2Trajectory
        self.iANPR2Trajectory.restype = ctypes.c_void_p
        self.iANPR2Trajectory.argtypes = (ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int,)
        #bool iANPR2TrajectoryRelease(void* object);
        self.iANPR2TrajectoryRelease = self.lib.iANPR2TrajectoryRelease
        self.iANPR2TrajectoryRelease.restype = ctypes.c_bool
        self.iANPR2TrajectoryRelease.argtypes = (ctypes.c_void_p,)
        #bool iANPR2TrajectoryProcessJSON(void* object, char* jsonNumbers, char* jsonObjects);
        self.iANPR2TrajectoryProcessJSON = self.lib.iANPR2TrajectoryProcessJSON
        self.iANPR2TrajectoryProcessJSON.restype = ctypes.c_bool
        self.iANPR2TrajectoryProcessJSON.argtypes = (ctypes.c_void_p,ctypes.c_char_p,ctypes.c_char_p,)
        #int iANPR2TrajectoryGetResultJSON(void* object, char* outBuf, int sizeBuf);
        self.iANPR2TrajectoryGetResultJSON = self.lib.iANPR2TrajectoryGetResultJSON
        self.iANPR2TrajectoryGetResultJSON.restype = ctypes.c_int
        self.iANPR2TrajectoryGetResultJSON.argtypes = (ctypes.c_void_p,ctypes.c_char_p,ctypes.c_int,)
        #int iANPR2CreateLineIntersection(void* object,int line1X1, int line1Y1, int line1X2, int line1Y2,
        #int line2X1, int line2Y1, int line2X2, int line2Y2);
        self.iANPR2CreateLineIntersection = self.lib.iANPR2CreateLineIntersection
        self.iANPR2CreateLineIntersection.restype = ctypes.c_int
        self.iANPR2CreateLineIntersection.argtypes = (ctypes.c_void_p,ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int, \
            ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int,)
        #int iANPR2GetLineIntersection(void* object, int indexTr);
        self.iANPR2GetLineIntersection = self.lib.iANPR2GetLineIntersection
        self.iANPR2GetLineIntersection.restype = ctypes.c_int
        self.iANPR2GetLineIntersection.argtypes = (ctypes.c_void_p,ctypes.c_int,)

        self.ianpr2 = None
        self.trajectory = None

        # Версия
        size = 1000
        p = ctypes.create_string_buffer(size)
        self.iANPR2Version(p,size)
        logger.info(p.value.decode("ascii"))


    def __del__(self):
        if not self.trajectory is None:
            if self.iANPR2TrajectoryRelease(self.trajectory):
                logger.info("Object Trajectory deleted")

        if not self.ianpr2 is None:
            if self.iANPR2ReleaseP(self.ianpr2):
                logger.info("Object iANPR2 deleted")


    def initiANPR2Object(self,dataConfig,lic) -> bool:
        er = ctypes.c_int()
        self.ianpr2 = self.iANPR2Init(bytes(dataConfig,'ascii'),bytes(lic,'ascii'),ctypes.byref(er))
        if self.ianpr2 != None:
            logger.info("Object iANPR2 loaded")
            return True
        logger.error("Object iANPR2 not loaded: "+ str(er))
        return False

    def setSettings(self, settings) -> bool:
        s = json.dumps(settings)
        
        if self.iANPR2SettingsJSON(self.ianpr2,bytes(s,'ascii')):
            logger.info("iANPR2Settings installed")
            return True
        logger.error("iANPR2Settings not loaded")
        return False

    def putImage(self, img) -> bool:
        img_str = cv2.imencode('.bmp', img)[1].tostring() 
        res = self.anpr2AddImage(self.ianpr2,img_str,len(img_str))
        if res == 0:
            logger.info("Image added")
            return True
        logger.error("Image not added. Error = "+str(res))
        return False

    def inference(self) -> bool:
        res = self.anpr2inference(self.ianpr2)
        if res == 0:
            logger.info("Inference true")
            return True
        logger.error("Inference error = "+str(res))
        return False

    def inferenceFirst(self) -> bool:
        res = self.anpr2inferenceFirstStep(self.ianpr2)
        if res == 0:
            logger.info("Inference FirstStep true")
            return True
        logger.error("Inference FirstStep error = "+str(res))
        return False

    def inferenceSecond(self) -> bool:
        res = self.anpr2inferenceSecondStep(self.ianpr2)
        if res == 0:
            logger.info("Inference SecondStep true")
            return True
        logger.error("Inference SecondStep error = "+str(res))
        return False

    def getResult(self,code = "ascii") -> str:       
        size = 10000
        p = ctypes.create_string_buffer(size)
        if self.anpr2GetResultJSON(self.ianpr2,p,size) != 0:
            return ""
        
        return p.value.decode(code)

    def getAddResult(self) -> str:       
        size = 10000
        p = ctypes.create_string_buffer(size)
        if self.anpr2GetAddResultJSON(self.ianpr2,p,size) != 0:
            return ""
        
        return p.value.decode("ascii")

    def getMemResult(self,code = "ascii") -> str:       
        size = 10000
        p = ctypes.create_string_buffer(size)
        if self.anpr2GetResultMemJSON(self.ianpr2,p,size) != 0:
            return ""
        return p.value.decode(code)

    def initTrajectory(self, widthImage, heightImage, tLimitTime, tLimitFrames, typeSpeed) -> bool:                
        self.trajectory = self.iANPR2Trajectory(widthImage, heightImage, tLimitTime, tLimitFrames, typeSpeed)
        if self.trajectory != None:
            logger.info("Object Trajectory loaded")
            return True
        logger.error("Object Trajectory not loaded! ")
        return False

    def trajectoryProcess(self, jsonNumbers, jsonObjects,code = "ascii") -> bool:   
        if self.iANPR2TrajectoryProcessJSON(self.trajectory, bytes(jsonNumbers,code),bytes(jsonObjects,code)):
            logger.info("iANPR2TrajectoryProcessJSON ok")
            return True
        logger.error("iANPR2TrajectoryProcessJSON error")
        return False

    def getTrajectoryResult(self,code = "ascii") -> str:
        size = 10000
        p = ctypes.create_string_buffer(size)
        if self.iANPR2TrajectoryGetResultJSON(self.trajectory,p,size) != 0:
            return ""
        
        return p.value.decode(code)

    def createLineIntersection(self, line1X1, line1Y1, line1X2, line1Y2,
                              line2X1, line2Y1, line2X2, line2Y2) -> bool:
        if self.iANPR2CreateLineIntersection(self.trajectory, line1X1, line1Y1, line1X2, line1Y2,
                              line2X1, line2Y1, line2X2, line2Y2) == 0:
            return True
        return False

    def getLineIntersection(self, indexTr) -> int:
        return self.iANPR2GetLineIntersection(self.trajectory, indexTr)