// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "opencv_c_wraper.h"

#ifndef USE_OPENCV

int image_read(const char *img_path, c_mat_t *img) { return -1; }
int image_resize(const c_mat_t *src_img, c_mat_t *dst_img, const int width, const int height) { return -1; }
int image_save(const char *img_path, c_mat_t *img) { return -1; }
int image_free(c_mat_t *img) { return -1; }
int image_add_rectangles(c_mat_t *img, rectangle_t rects[], int classes[], int num, int thickness) { return -1; }

#else

#include <opencv2/opencv.hpp>
#include <algorithm>

int image_read(const char *img_path, c_mat_t *img) {
    if (img_path == nullptr || img == nullptr) {
        return - 1;
    }

    cv::Mat mat = cv::imread(img_path);
    if (mat.data == NULL) {
        return -1;
    }

    img->mat_channels = mat.channels();
    img->mat_width = mat.size().width;
    img->mat_height = mat.size().height;
    img->mat_type = mat.type();
    img->mat_data_size = img->mat_channels * img->mat_width * img->mat_height;
    img->mat_data = (unsigned char *)malloc(sizeof(unsigned char) * img->mat_data_size);
    for (int i = 0; i < img->mat_data_size; ++i) {
        img->mat_data[i] = mat.data[i];
    }

    return 0;
}

int image_resize(const c_mat_t *src_img, c_mat_t *dst_img, const int width, const int height) {
    if (src_img == nullptr || dst_img == nullptr) {
        return -1;
    }

    cv::Mat mat_src(cv::Size(src_img->mat_width, src_img->mat_height), src_img->mat_type, src_img->mat_data);

    cv::Mat mat_dst;
    cv::resize(mat_src, mat_dst, cv::Size(width, height));
    if (mat_dst.data) {
        dst_img->mat_channels = mat_dst.channels();
        dst_img->mat_width = mat_dst.size().width;
        dst_img->mat_height = mat_dst.size().height;
        dst_img->mat_type = mat_dst.type();
        dst_img->mat_data_size = dst_img->mat_channels * dst_img->mat_width * dst_img->mat_height;
        dst_img->mat_data = (unsigned char *)malloc(sizeof(unsigned char) * dst_img->mat_data_size);
        for (int i = 0; i < dst_img->mat_data_size; ++i) {
            dst_img->mat_data[i] = mat_dst.data[i];
        }
    } else {
        return -1;
    }

    return 1;
}

int image_save(const char *img_path, c_mat_t *img) {
    cv::Mat mat(cv::Size(img->mat_width, img->mat_height), img->mat_type, img->mat_data);
    return cv::imwrite(img_path, mat);
}

int image_free(c_mat_t *img) {
    if (img) {
        free(img->mat_data);
        img->mat_data = NULL;
    }
    return -1;
}

int image_add_rectangles(c_mat_t *img, rectangle_t rects[], int classes[], int num, int thickness) {
    int colors_num = 21;
    color_t colors[21] = {  // colors to be used for bounding boxes
        { 128, 64,  128 },
        { 232, 35,  244 },
        { 70,  70,  70 },
        { 156, 102, 102 },
        { 153, 153, 190 },
        { 153, 153, 153 },
        { 30,  170, 250 },
        { 0,   220, 220 },
        { 35,  142, 107 },
        { 152, 251, 152 },
        { 180, 130, 70 },
        { 60,  20,  220 },
        { 0,   0,   255 },
        { 142, 0,   0 },
        { 70,  0,   0 },
        { 100, 60,  0 },
        { 90,  0,   0 },
        { 230, 0,   0 },
        { 32,  11,  119 },
        { 0,   74,  111 },
        { 81,  0,   81 }
    };

    for (int i = 0; i < num; i++) {
        int x = rects[i].x_min;
        int y = rects[i].y_min;
        int w = rects[i].rect_width;
        int h = rects[i].rect_height;

        int cls = classes[i] % colors_num;  // color of a bounding box line

        if (x < 0) x = 0;
        if (y < 0) y = 0;
        if (w < 0) w = 0;
        if (h < 0) h = 0;

        if (x >= img->mat_width) { x = img->mat_width - 1; w = 0; thickness = 1; }
        if (y >= img->mat_height) { y = img->mat_height - 1; h = 0; thickness = 1; }

        if ((x + w) >= img->mat_width) { w = img->mat_width - x - 1; }
        if ((y + h) >= img->mat_height) { h = img->mat_height - y - 1; }

        thickness = std::min(std::min(thickness, w / 2 + 1), h / 2 + 1);

        size_t shift_first;
        size_t shift_second;
        for (int t = 0; t < thickness; t++) {
            shift_first = (y + t) * img->mat_width * 3;
            shift_second = (y + h - t) * img->mat_width * 3;
            for (int ii = x; ii < x + w + 1; ii++) {
                img->mat_data[shift_first + ii * 3] = colors[cls].r;
                img->mat_data[shift_first + ii * 3 + 1] = colors[cls].g;
                img->mat_data[shift_first + ii * 3 + 2] = colors[cls].b;
                img->mat_data[shift_second + ii * 3] = colors[cls].r;
                img->mat_data[shift_second + ii * 3 + 1] = colors[cls].g;
                img->mat_data[shift_second + ii * 3 + 2] = colors[cls].b;
            }
        }

        for (int t = 0; t < thickness; t++) {
            shift_first = (x + t) * 3;
            shift_second = (x + w - t) * 3;
            for (int ii = y; ii < y + h + 1; ii++) {
                img->mat_data[shift_first + ii * img->mat_width * 3] = colors[cls].r;
                img->mat_data[shift_first + ii * img->mat_width * 3 + 1] = colors[cls].g;
                img->mat_data[shift_first + ii * img->mat_width * 3 + 2] = colors[cls].b;
                img->mat_data[shift_second + ii * img->mat_width * 3] = colors[cls].r;
                img->mat_data[shift_second + ii * img->mat_width * 3 + 1] = colors[cls].g;
                img->mat_data[shift_second + ii * img->mat_width * 3 + 2] = colors[cls].b;
            }
        }
    }
    return 0;
}

#endif  // USE_OPENCV
