/*
 # This file is part of the Astrometry.net suite.
 # Licensed under a 3-clause BSD style license - see LICENSE
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>

#include "os-features.h"
#include "histogram2d.h"
#include "errors.h"

static histogram2d* hist_new(int nx, int ny) {
    histogram2d* h = calloc(1, sizeof(histogram2d));
    if (!h) {
        ERROR("Couldn't allocate a histogram2d.");
        return NULL;
    }
    h->hist = calloc(nx*ny, sizeof(int));
    if (!h->hist) {
        ERROR("Couldn't allocate a histogram2d with %ix%i bins.", nx, ny);
        free(h);
        return NULL;
    }
    h->NX = nx;
    h->NY = ny;
    return h;
}


histogram2d* histogram2d_new_nbins(double minX, double maxX, int NbinsX,
                                   double minY, double maxY, int NbinsY) {
    double binsizeX = (maxX - minX) / (double)(NbinsX);
    double binsizeY = (maxY - minY) / (double)(NbinsY);
    histogram2d* h = hist_new(NbinsX, NbinsY);
    h->minx = minX;
    //h->maxx = maxX;
    h->miny = minY;
    //h->maxy = maxY;
    h->binsizex = binsizeX;
    h->binsizey = binsizeY;
    h->NX = NbinsX;
    h->NY = NbinsY;
    h->edgex = HIST2D_TRUNCATE;
    h->edgey = HIST2D_TRUNCATE;
    return h;
}


void histogram2d_free(histogram2d* h) {
    free(h->hist);
    free(h);
}

int histogram2d_add(histogram2d* h, double x, double y) {
    int binx = (x - h->minx) / h->binsizex;
    int biny = (y - h->miny) / h->binsizey;
    int bin;
    if (h->edgex == HIST2D_TRUNCATE)
        binx = MIN(h->NX-1, MAX(0, binx));
    else if (h->edgex == HIST2D_DISCARD) {
        if (binx < 0 || binx >= h->NX)
            return HIST2D_DISCARDED_X;
    } else
        assert(0);

    if (h->edgey == HIST2D_TRUNCATE)
        biny = MIN(h->NY-1, MAX(0, biny));
    else if (h->edgey == HIST2D_DISCARD) {
        if (biny < 0 || biny >= h->NY)
            return HIST2D_DISCARDED_Y;
    } else
        assert(0);

    bin = biny * h->NX + binx;
    h->hist[bin]++;
    return bin;
}

void histogram2d_set_x_edges(histogram2d* h, int edgepolicy) {
    h->edgex = edgepolicy;
}

void histogram2d_set_y_edges(histogram2d* h, int edgepolicy) {
    h->edgey = edgepolicy;
}

