#include <Python.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <numpy/arrayobject.h>

#include <iostream>

#include "HoG.cpp"

extern "C" {

static PyObject *hogpy_hog(PyObject *self, PyObject *args) 
{
	PyObject *pixels_obj;
	int nb_bins, block_size, unsigned_dirs;
        double cwidth, clip_val;
        size_t img_size[] = {50, 25}; 
	size_t stride = 50; 
	bool grayscale = 1;

	// Parse the passed arguments
	if(!PyArg_ParseTuple(args, "Oidiid", &pixels_obj, &nb_bins, &cwidth, &block_size, &unsigned_dirs, &clip_val)) return 0;

	// Interpret the first argument as numpy array
	PyArrayObject *pixels_array = (PyArrayObject*)PyArray_FROM_OTF(pixels_obj, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY); 
    	if(pixels_array == NULL)
	{
		Py_XDECREF(pixels_array);
		return 0;
	}

	size_t n = (size_t)PyArray_DIM(pixels_array, 0);
	// check the dimension of the given image
	if(n != img_size[0] * img_size[1])
	{
		PyErr_SetString(PyExc_ValueError, "The image has the wrong dimension.");
		return 0;
	}

	// Get pointer to the pixels array as C data
	double *pixels = (double*)PyArray_DATA(pixels_array);

	// create the output array
	size_t numFeatures = getNumFeatures(img_size, nb_bins, cwidth, block_size);
	double out[numFeatures];
	
	// Run the HoG algorithm
	HoG(pixels, nb_bins, cwidth, block_size, unsigned_dirs, clip_val, img_size, stride, out, grayscale);
	
	// cleanup
	Py_DECREF(pixels_array);

	// Return the out array. We build a Python list and append each element of out as a Python float
	PyObject *lst = PyList_New(numFeatures); 
	if(!lst) return 0;
	for(size_t i = 0;i < numFeatures;i++)
	{
    		PyObject *num = PyFloat_FromDouble(out[i]);
    		if(!num)
		{
        		Py_DECREF(lst);
        		return 0;
    		}
    		if(PyList_SET_ITEM(lst, i, num) < 0)
		{
			Py_DECREF(lst);
			return 0;
		}
	}
	return lst;
}	

static PyMethodDef HogpyMethods[] = {
    {"hog", hogpy_hog, METH_VARARGS,
     "Compute the HOG feature vector for an image."},
    {NULL, NULL, 0, NULL}};

static struct PyModuleDef hogymodule = {
    PyModuleDef_HEAD_INIT, "hogpy", /* name of module */
    NULL,                           /* module documentation, may be NULL */
    -1, /* size of per-interpreter state of the module,
           or -1 if the module keeps state in global variables. */
    HogpyMethods};

PyMODINIT_FUNC PyInit_hogpy() {
  PyObject *m = PyModule_Create(&hogymodule);
  if (m == nullptr)
    return nullptr;

  import_array();

  return m;
}
}
