
import cv2
import numpy as np
import argparse
import onnxruntime as ort
from pathlib import Path
from tqdm import tqdm
import time
import sys
import os
import requests
from utils.utils import send_notifycation

def getFile(ruleFile):
    if getattr(sys, 'frozen', False):
        absPath = os.path.dirname(os.path.abspath(sys.executable))
    elif __file__:
        absPath = os.path.dirname(os.path.abspath(__file__))
    else:
        absPath = ''
    return os.path.join(absPath,ruleFile)

def checkModel(model):
    """
    【功能】检查模型是否存在
    【参数】
        model: str   必选,模型名称
    【输入/输出】
        True: 模型存在
        False: 模型不存在
    """
    # 先检查本地是否存在该文件模型，不存在则查看网络数据库是否存在该模型，存在则下载然后返回该模型
    if not os.path.exists(getFile(model)):
            send_notifycation('模型不存在，正在下载模型...')
            url = 'https://gitee.com/JiangNoah/emc/raw/master/model.json'
            r = requests.get(url)
            model_dict = r.json()# model_dict = {models:[{'name':model,'url':url}]}
            #检查是否存在该模型的name
            models = model_dict["models"]
            url_ = ''
            for m in models:
                if m["name"] == model:
                    url_ = m["url"]
                    break
            if url_ == '':
                send_notifycation('模型不存在')
                return getFile(model)
            else:
                send_notifycation('模型下载中...')
                r = requests.get(url_)
                with open(getFile(model), 'wb') as f:
                    f.write(r.content)
                send_notifycation('模型下载完成')
                return getFile(model)
    else:
        return getFile(model)


class PicoDet():
    def __init__(self,
                 model_pb_path,
                 label_path,
                 prob_threshold=0.4,
                 iou_threshold=0.3):
        self.classes = list(
            map(lambda x: x.strip(), open(getFile(label_path), 'r').readlines()))
        self.num_classes = len(self.classes)
        self.prob_threshold = prob_threshold
        self.iou_threshold = iou_threshold
        self.mean = np.array(
            [103.53, 116.28, 123.675], dtype=np.float32).reshape(1, 1, 3)
        self.std = np.array(
            [57.375, 57.12, 58.395], dtype=np.float32).reshape(1, 1, 3)
        so = ort.SessionOptions()
        so.log_severity_level = 3
        self.net = ort.InferenceSession(checkModel(model_pb_path), so)
        inputs_name = [a.name for a in self.net.get_inputs()]
        inputs_shape = {
            k: v.shape
            for k, v in zip(inputs_name, self.net.get_inputs())
        }
        self.input_shape = inputs_shape['image'][2:]

    def _normalize(self, img):
        img = img.astype(np.float32)
        img = (img / 255.0 - self.mean / 255.0) / (self.std / 255.0)
        return img

    def resize_image(self, srcimg, keep_ratio=False):
        top, left, newh, neww = 0, 0, self.input_shape[0], self.input_shape[1]
        origin_shape = srcimg.shape[:2]
        im_scale_y = newh / float(origin_shape[0])
        im_scale_x = neww / float(origin_shape[1])
        img_shape = np.array([
            [float(self.input_shape[0]), float(self.input_shape[1])]
        ]).astype('float32')
        scale_factor = np.array([[im_scale_y, im_scale_x]]).astype('float32')

        if keep_ratio and srcimg.shape[0] != srcimg.shape[1]:
            hw_scale = srcimg.shape[0] / srcimg.shape[1]
            if hw_scale > 1:
                newh, neww = self.input_shape[0], int(self.input_shape[1] /
                                                      hw_scale)
                img = cv2.resize(
                    srcimg, (neww, newh), interpolation=cv2.INTER_AREA)
                left = int((self.input_shape[1] - neww) * 0.5)
                img = cv2.copyMakeBorder(
                    img,
                    0,
                    0,
                    left,
                    self.input_shape[1] - neww - left,
                    cv2.BORDER_CONSTANT,
                    value=0)  # add border
            else:
                newh, neww = int(self.input_shape[0] *
                                 hw_scale), self.input_shape[1]
                img = cv2.resize(
                    srcimg, (neww, newh), interpolation=cv2.INTER_AREA)
                top = int((self.input_shape[0] - newh) * 0.5)
                img = cv2.copyMakeBorder(
                    img,
                    top,
                    self.input_shape[0] - newh - top,
                    0,
                    0,
                    cv2.BORDER_CONSTANT,
                    value=0)
        else:
            img = cv2.resize(
                srcimg, self.input_shape, interpolation=cv2.INTER_AREA)

        return img, img_shape, scale_factor

    def get_color_map_list(self, num_classes):
        color_map = num_classes * [0, 0, 0]
        for i in range(0, num_classes):
            j = 0
            lab = i
            while lab:
                color_map[i * 3] |= (((lab >> 0) & 1) << (7 - j))
                color_map[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j))
                color_map[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j))
                j += 1
                lab >>= 3
        color_map = [color_map[i:i + 3] for i in range(0, len(color_map), 3)]
        return color_map

    def detect(self, srcimg, show_result=False):
        img, im_shape, scale_factor = self.resize_image(srcimg)
        img = self._normalize(img)

        blob = np.expand_dims(np.transpose(img, (2, 0, 1)), axis=0)

        inputs_dict = {
            'im_shape': im_shape,
            'image': blob,
            'scale_factor': scale_factor
        }
        inputs_name = [a.name for a in self.net.get_inputs()]
        net_inputs = {k: inputs_dict[k] for k in inputs_name}

        outs = self.net.run(None, net_inputs)

        outs = np.array(outs[0])
        expect_boxes = (outs[:, 1] > 0.5) & (outs[:, 0] > -1)
        np_boxes = outs[expect_boxes, :]

        color_list = self.get_color_map_list(self.num_classes)
        clsid2color = {}

        result = []
        for i in range(np_boxes.shape[0]):
            classid, conf = int(np_boxes[i, 0]), np_boxes[i, 1]
            result.append({
                'classid': self.classes[classid],
                'conf': str(round(conf, 3)),
            })

        if(show_result):
            for i in range(np_boxes.shape[0]):
                classid, conf = int(np_boxes[i, 0]), np_boxes[i, 1]
                xmin, ymin, xmax, ymax = int(np_boxes[i, 2]), int(np_boxes[
                    i, 3]), int(np_boxes[i, 4]), int(np_boxes[i, 5])

                if classid not in clsid2color:
                    clsid2color[classid] = color_list[classid]
                color = tuple(clsid2color[classid])

                cv2.rectangle(
                    srcimg, (xmin, ymin), (xmax, ymax), color, thickness=2)
                print(self.classes[classid] + ': ' + str(round(conf, 3)))
                cv2.putText(
                    srcimg,
                    self.classes[classid] + ':' + str(round(conf, 3)), (xmin,
                                                                        ymin - 10),
                    cv2.FONT_HERSHEY_SIMPLEX,
                    0.8, (0, 255, 0),
                    thickness=2)

            return [result,srcimg]
        else:
            
            return result

    def detect_folder(self, img_fold, result_path):
        img_fold = Path(img_fold)
        result_path = Path(result_path)
        result_path.mkdir(parents=True, exist_ok=True)

        img_name_list = filter(
            lambda x: str(x).endswith(".png") or str(x).endswith(".jpg"),
            img_fold.iterdir(), )
        img_name_list = list(img_name_list)
        print(f"find {len(img_name_list)} images")

        for img_path in tqdm(img_name_list):
            img = cv2.imread(str(img_path))

            srcimg = self.detect(img,True)
            save_path = str(result_path / img_path.name.replace(".png", ".jpg"))
            cv2.imwrite(save_path, srcimg)
    
    def detect_img(self, img,show_result=False):
        # img = cv2.imread(img)
        # img_path = Path(img_path)
        # print(f"find {img_path} images")
        
        
        if(show_result):
            [result,srcimg] = self.detect(img,show_result)
            return [result,srcimg]
        else:
            result = self.detect(img,show_result)
            return result
            # result_path = Path(result_path)
            # result_path.mkdir(parents=True, exist_ok=True)
            # save_path = str(result_path / "result.jpg")
            # cv2.imwrite(save_path, srcimg)
        #     return srcimg
        # else:

    def crop_2_224(img):
        height=len(img)
        width=len(img[0])
        if(height>224 and width>224):
            y0 = height/2
            x0 = width/2
            x1 = x0-112
            y1 = y0-112
            x2 = x0+112
            y2 = y0+112
            img = img[y1:y2, x1:x2]
        return img
        
