/*
   Copyright (C) 2009 Red Hat, Inc.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef RED_BITMAP_UTILS_RGB16
#define PIXEL rgb16_pixel_t
#define FNAME(name) name##_rgb16
#define GET_r(pix) (((pix) >> 10) & 0x1f)
#define GET_g(pix) (((pix) >> 5) & 0x1f)
#define GET_b(pix) ((pix) & 0x1f)
#endif

#if defined(RED_BITMAP_UTILS_RGB24) || defined(RED_BITMAP_UTILS_RGB32)
#define GET_r(pix) ((pix).r)
#define GET_g(pix) ((pix).g)
#define GET_b(pix) ((pix).b)
#endif

#ifdef RED_BITMAP_UTILS_RGB24
#define PIXEL rgb24_pixel_t
#define FNAME(name) name##_rgb24
#endif

#ifdef RED_BITMAP_UTILS_RGB32
#define PIXEL rgb32_pixel_t
#define FNAME(name) name##_rgb32
#endif


#define SAME_PIXEL_WEIGHT 0.5
#define NOT_CONTRAST_PIXELS_WEIGHT -0.25
#define CONTRAST_PIXELS_WEIGHT 1.0

#ifndef RED_BITMAP_UTILS_RGB16
#define CONTRAST_TH 60
#else
#define CONTRAST_TH 8
#endif
#define CONTRASTING(n) ((n) <= -CONTRAST_TH || (n) >= CONTRAST_TH)


#define SAMPLE_JUMP 15

static const double FNAME(PIX_PAIR_SCORE)[] = {
    SAME_PIXEL_WEIGHT,
    CONTRAST_PIXELS_WEIGHT,
    NOT_CONTRAST_PIXELS_WEIGHT,
};

// return 0 - equal, 1 - for contrast, 2 for no contrast (PIX_PAIR_SCORE is defined accordingly)
static inline int FNAME(pixelcmp)(PIXEL p1, PIXEL p2)
{
    int diff, any_different;

    diff = GET_r(p1) - GET_r(p2);
    any_different = diff;
    if (CONTRASTING(diff)) {
        return 1;
    }

    diff = GET_g(p1) - GET_g(p2);
    any_different |= diff;
    if (CONTRASTING(diff)) {
        return 1;
    }

    diff = GET_b(p1) - GET_b(p2);
    any_different |= diff;
    if (CONTRASTING(diff)) {
        return 1;
    }

    if (!any_different) {
        return 0;
    } else {
        return 2;
    }
}

static inline double FNAME(pixels_square_score)(PIXEL *line1, PIXEL *line2)
{
    double ret;
    int any_different = 0;
    int cmp_res;
    cmp_res = FNAME(pixelcmp)(*line1, line1[1]);
    any_different |= cmp_res;
    ret  = FNAME(PIX_PAIR_SCORE)[cmp_res];
    cmp_res = FNAME(pixelcmp)(*line1, *line2);
    any_different |= cmp_res;
    ret += FNAME(PIX_PAIR_SCORE)[cmp_res];
    cmp_res = FNAME(pixelcmp)(*line1, line2[1]);
    any_different |= cmp_res;
    ret += FNAME(PIX_PAIR_SCORE)[cmp_res];

    // ignore squares where all pixels are identical
    if (!any_different) {
        ret = 0;
    }

    return ret;
}

static void FNAME(compute_lines_gradual_score)(PIXEL *lines, int width, int num_lines,
                                               double *o_samples_sum_score, int *o_num_samples)
{
    int jump = (SAMPLE_JUMP % width) ? SAMPLE_JUMP : SAMPLE_JUMP - 1;
    PIXEL *cur_pix = lines + width / 2;
    PIXEL *bottom_pix;
    PIXEL *last_line = lines + (num_lines - 1) * width;

    if ((width <= 1) || (num_lines <= 1)) {
        *o_num_samples = 1;
        *o_samples_sum_score = 1.0;
        return;
    }

    *o_samples_sum_score = 0;
    *o_num_samples = 0;

    while (cur_pix < last_line) {
        if ((cur_pix + 1 - lines) % width == 0) { // last pixel in the row
            cur_pix--; // jump is bigger than 1 so we will not enter endless loop
        }
        bottom_pix = cur_pix + width;
        (*o_samples_sum_score) += FNAME(pixels_square_score)(cur_pix, bottom_pix);
        (*o_num_samples)++;
        cur_pix += jump;
    }

    (*o_num_samples) *= 3;
}

#undef PIXEL
#undef FNAME
#undef GET_r
#undef GET_g
#undef GET_b
#undef RED_BITMAP_UTILS_RGB16
#undef RED_BITMAP_UTILS_RGB24
#undef RED_BITMAP_UTILS_RGB32
#undef SAMPLE_JUMP
#undef CONTRAST_TH
#undef SAME_PIXEL_WEIGHT
#undef NOT_CONTRAST_PIXELS_WEIGHT
