/*
 * Copyright 2020 Rockchip Electronics Co. LTD
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "iep2_gmv.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "mpp_common.h"
#include "mpp_buffer.h"

#include "iep2_api.h"

void iep2_sort(uint32_t bin[], uint32_t map[], int size)
{
    int i, m, n;
    uint32_t *dat = malloc(size * sizeof(uint32_t));

    for (i = 0; i < size; ++i) {
        map[i] = i;
        dat[i] = bin[i];
    }

    for (m = 0; m < size; ++m) {
        int max = m;
        uint32_t temp;
        int p;

        for (n = m + 1; n < size; ++n)
            if (dat[n] > dat[max])
                max = n;
        // Put found minimum element in its place
        temp = dat[m];
        p = map[m];

        map[m] = map[max];
        map[max] = p;
        dat[m] = dat[max];
        dat[max] = temp;
    }

    free(dat);
}

static int iep2_osd_check(int8_t *mv, int w, int sx, int ex, int sy, int ey,
                          int *mvx)
{
    /* (28 + 27) * 4 + 1 */
    uint32_t hist[221];
    uint32_t map[221];
    int total = (ey - sy + 1) * (ex - sx + 1);
    int non_zero = 0;
    int domin = 0;
    int i, j;

    memset(hist, 0, sizeof(hist));

    for (i = sy; i <= ey; ++i) {
        for (j = sx; j <= ex; ++j) {
            int8_t v = mv[i * w + j];
            uint32_t idx = v + 28 * 4;

            if (idx >= MPP_ARRAY_ELEMS(hist)) {
                mpp_log("invalid mv at (%d, %d)\n", j, i);
                continue;
            }
            hist[idx]++;
        }
    }

    non_zero = total - hist[28 * 4];

    iep2_sort(hist, map, MPP_ARRAY_ELEMS(hist));

    domin = hist[map[0]];
    if (map[0] + 1 < MPP_ARRAY_ELEMS(hist))
        domin += hist[map[0] + 1];
    if (map[0] >= 1)
        domin += hist[map[0] - 1];

    iep_dbg_trace("total tiles in current osd: %d, non-zero %d\n",
                  total, non_zero);

    if (domin * 4 < non_zero * 3) {
        iep_dbg_trace("main mv %d count %d not dominant\n",
                      map[0] - 28 * 4, domin);
        return 0;
    }

    *mvx = map[0] - 28 * 4;

    return 1;
}

void iep2_set_osd(struct iep2_api_ctx *ctx, struct mv_list *ls)
{
    uint32_t i, j;
    int idx = 0;

    int sx[8];
    int ex[8];
    int sy[8];
    int ey[8];

    uint32_t osd_tile_cnt = 0;
    int mvx;
    int8_t *pmv = mpp_buffer_get_ptr(ctx->mv_buf);

    memset(ls, 0, sizeof(*ls));

    for (i = 0; i < ctx->output.dect_osd_cnt; ++i) {
        sx[i] = ctx->output.x_sta[i];
        ex[i] = ctx->output.x_end[i];
        sy[i] = ctx->output.y_sta[i];
        ey[i] = ctx->output.y_end[i];
    }

    /* Hardware isn't supporting subtitle regions overlap. */
    for (i = 0; i < ctx->output.dect_osd_cnt; ++i) {
        for (j = i + 1; j < ctx->output.dect_osd_cnt; ++j) {
            if (sy[j] == ey[i]) {
                if (ex[i] - sx[i] > ex[j] - sx[j]) {
                    sy[j]++;
                } else {
                    ey[i]--;
                }
            } else {
                break;
            }
        }
    }

    for (i = 0; i < ctx->output.dect_osd_cnt; ++i) {
        if (!iep2_osd_check(pmv, ctx->params.tile_cols,
                            sx[i], ex[i], sy[i], ey[i], &mvx))
            continue;

        ctx->params.osd_x_sta[idx] = sx[i];
        ctx->params.osd_x_end[idx] = ex[i];
        ctx->params.osd_y_sta[idx] = sy[i];
        ctx->params.osd_y_end[idx] = ey[i];

        osd_tile_cnt += (ex[i] - sx[i] + 1) * (ey[i] - sy[i] + 1);

        ls->mv[idx] = mvx;
        ls->vld[idx] = 1;

        iep_dbg_trace("[%d] from [%d,%d][%d,%d] to [%d,%d][%d,%d] mv %d\n", i,
                      sx[i], ex[i], sy[i], ey[i],
                      ctx->params.osd_x_sta[idx], ctx->params.osd_x_end[idx],
                      ctx->params.osd_y_sta[idx], ctx->params.osd_y_end[idx],
                      ls->mv[idx]);
        idx++;
    }

    ctx->params.osd_area_num = idx;
    ls->idx = idx;

    iep_dbg_trace("osd tile count %d comb %d\n",
                  osd_tile_cnt, ctx->output.out_osd_comb_cnt);
    if (osd_tile_cnt * 2 > ctx->output.out_osd_comb_cnt * 3) {
        memset(ctx->params.comb_osd_vld, 0, sizeof(ctx->params.comb_osd_vld));
    } else {
        memset(ctx->params.comb_osd_vld, 1, sizeof(ctx->params.comb_osd_vld));
    }
}

