import config, histogram, limits, canny, hough, util

int def locate_min_x(Image *image):
    B *data = image->data.b
    int w = image->w
    int h = image->h
    int x = 0, x_ = 0
    int minsum = INT_MAX
    for int i = 0; i < w; i++:
        V sum = 0
        for int j = 0; j < h; j++:
            sum += data[j * w + i]
        if sum < minsum:
            minsum = sum
            x = i
        if sum == minsum:
            x_ = i
    return (x + x_) / 2
    
int def locate_min_y(Image *image):
    B *data = image->data.b
    int w = image->w
    int h = image->h
    int y = 0, y_ = 0
    int minsum = INT_MAX
    for int j = 0; j < h; j++:
        V sum = 0
        for int i = 0; i < h; i++:
            sum += data[j * w + i]
        if sum < minsum:
            minsum = sum
            y = j
        if sum == minsum:
            y_ = j
    return (y + y_) / 2

Image *def binarize_pupil(Image *image):
    #int x = locate_min_x(image)
    #int y = locate_min_y(image)

    #int *histogram = get_histogram(image, w, h)

    # TODO

    return image

static int def count(Image *image, int x, y, max_r, min_c):
    int w = image->w
    int h = image->h
    int n = 0
    int s = 0
    if image->data.b[x + y * w] >= min_c:
        n++
    else:
        return 0
    for int r = 0; r < max_r; r++:
        int on = n
        s += 2
        x -= 1
        y -= 1
        int dx[4] = {1, 0, -1 ,0}
        int dy[4] = {0, 1, 0, -1}
        for int j = 0; j < 4; j++:
            for int i = 0; i < s; i++:
                if x >= 0 and y >= 0 and x < w and y < h:
                    if image->data.b[x + y * w] >= min_c:
                        n++
                x += dx[j]
                y += dy[j]
        if on == n: # disconnected
            return n
    return 0

static int def fill(Image *image, int x, y, max_r, min_c, c):
    int w = image->w
    int h = image->h
    int n = 0
    int s = 0
    if image->data.b[x + y * w] >= min_c:
        n++
        image->data.b[x + y * w] = c
    else:
        return 0
    for int r = 0; r < max_r; r++:
        int on = n
        s += 2
        x -= 1
        y -= 1
        int dx[4] = {1, 0, -1 ,0}
        int dy[4] = {0, 1, 0, -1}
        for int j = 0; j < 4; j++:
            for int i = 0; i < s; i++:
                if x >= 0 and y >= 0 and x < w and y < h:
                    if image->data.b[x + y * w] >= min_c:
                        n++
                        image->data.b[x + y * w] = c
                x += dx[j]
                y += dy[j]
        if on == n: # disconnected
            return n
    return 0

def blackout_reflections(Image *image, int w, h, int x, y, x_, y_):
    int sum = 0
    int sumc = 0
    for int j = y; j < y_; j++:
        for int i = x; i < x_; i++:
            sum += image->data.b[i + j * w]
            sumc++
    sum /= sumc
    for int j = y; j < y_; j++:
        for int i = x; i < x_; i++:
            int n = count(image, i, j, 5, 250)
            if n > 0:
                fill(image, i, j, 5, 150, sum)

Image *def find_pupil(Image const *orig_image, char const *what,
    int *px, *py, *pr):
    Image *image = image_copy(orig_image)
    #int x = locate_min_x(image)
    #int y = locate_min_y(image)
    int w = image->w
    int h = image->h

    int PUPIL_HOUGH_THRESHOLD = 200

    #blackout_reflections(image, w, h, x - 60, y - 60, x + 60, y + 60)

    # good for ubiris:
    adjust_luminance(image, w * h * 0.02, w * h * 0.04)

    #adjust_luminance(image, w * h * 0.04, w * h * 0.9)
    # good for casia v3
    #adjust_luminance(image, w * h * 0.04, 0)

    Image *accum = cumulate(image, 3, 3)
    # The inverse accum is to reduce shrinking of the pupil.
    invert(accum)
    Image *accum2 = cumulate(accum, 3, 3)
    invert(accum2)
    image_del(accum)
    accum = accum2
    accum->name = strdup(image->name)
    int ax, ay, bx, by

    if what and hasword(what, "pupilprep"):
        char name[MAX_PATH]
        get_image_name(image, "pupilprep", name)
        save_tiff_luminance(name, accum)

    int hrun = longest_horizontal_run(accum, w * 0.25, 127)
    int vrun = longest_vertical_run(accum, h * 0.25, 127)

    Image *result = canny(accum, 3, 15, 1, 1, what)

    if what and hasword(what, "pupilcanny"):
        char name[MAX_PATH]
        get_image_name(image, "pupilcanny", name)
        save_tiff_luminance(name, result)

    bool debug = false
    remove_streaks(result, what, 6, 1, 1, 5, 5, 10, 10, 3, 3, debug)

    if what and hasword(what, "pupilstreaks"):
        char name[MAX_PATH]
        get_image_name(image, "pupilstreaks", name)
        save_tiff_luminance(name, result)

    # Can't we do better? The lid has black pixels usually, so this bounds is
    # often much too big.
    bounds_bigger_than_threshold(result, 0, &ax, &ay, &bx, &by)

    # TODO: Better way for lower and upper bound?

    #int min_r = sqrt(black_pixels_count / pi)
    #int max_r = (bx - ax) / 2

    int min_r = min(hrun / 2, vrun / 2)
    # This can be far off if there's large reflections on the pupil
    int max_r = min_r + max(hrun / 2, vrun / 2)

    int border = min_r * 1.5 # else where would we fit the iris?
    if ax < border: ax = border
    if ay < border: ay = border
    if bx > w - 1 - border: bx = w - 1 - border
    if by > h - 1 - border: by = h - 1 - border

    printf("%d %d %d %d: [%d/%d] %d - %d\n", ax, ay, bx, by, hrun, vrun,
        min_r, max_r)
    Vector *circles = hough_circle(result, min_r, max_r, ax, bx, ay, by,
        PUPIL_HOUGH_THRESHOLD, 0, 0, 0,
        what,
        "pupilaccums", "pupilaccums")

    bool debug2 = false
    int cx = 0, cy = 0, cr = 0
    find_best_circle(circles, &cx, &cy, &cr, 1, w / 2, h / 2, h / 2, 0, debug2)

    Image *rgb = BtoRGB(orig_image)
    Color red = {255, 0, 0}
    draw_location(rgb, cx, cy, red)
    draw_circle(rgb, cx - cr, cy - cr, cx + cr, cy + cr, red)

    *px = cx
    *py = cy
    *pr = cr
    return rgb
