/*  
    This code is written by Davide Albanese <albanese@fbk.it>.
    (C) 2009 Fondazione Bruno Kessler - Via Santa Croce 77, 38100 Trento, ITALY.
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#include <Python.h>
#include <numpy/arrayobject.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>


int is_power(n, b)
{
  if (b == 0)
    {
      if (n == 1) 
	return 1;
      else
	return 0;
    }

  else if ((b == 1) || (n == 0) || (n == 1))
    return 1;
  
  else
    {
      while (((n % b) == 0) && (n != 1))
	n = n / b;
      
      if (n == 1)
	return 1;
      else
	return 0;
    }
}


static PyObject *misc_away(PyObject *self, PyObject *args, PyObject *keywds)
{
  PyObject *a = NULL; PyObject *aa = NULL;
  PyObject *b = NULL; PyObject *ba = NULL;
  double d;
  
  int *cidx;
  int not_away;
  int i, j, k;
  double *av, *bv;

  PyObject *ca = NULL;
  npy_intp c_dims[1];
  double *cv;
  npy_intp an, bn;
  
  static char *kwlist[] = {"a", "b", "d", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, keywds, "OOd", kwlist,
				   &a, &b, &d))
    return NULL;
  
  aa = PyArray_FROM_OTF(a, NPY_DOUBLE, NPY_IN_ARRAY);
  if (aa == NULL) return NULL;
  
  ba = PyArray_FROM_OTF(b, NPY_DOUBLE, NPY_IN_ARRAY);
  if (ba == NULL) return NULL;
  
  av = (double *) PyArray_DATA(aa);
  an = PyArray_DIM(aa, 0);
  
  bv = (double *) PyArray_DATA(ba);
  bn = PyArray_DIM(ba, 0);
  
  
  cidx = (int*) malloc(bn * sizeof(int));
  k = 0;
  
  for(i = 0; i < bn; i++)
    {
      not_away = 0;
      
      for(j = 0; j < an; j++)
	{
	  if(fabs(bv[i] - av[j]) < d)
	    {
	      not_away = 1;
	      break;
	    }
	}

      if(not_away == 0)
	{
	  cidx[k] = i;
	  k++; 
	}
    }

  c_dims[0] = (npy_intp) k;
  ca = PyArray_SimpleNew(1, c_dims, NPY_DOUBLE);
  cv = (double *) PyArray_DATA(ca);
  
  for(i = 0; i < k; i++)
    cv[i] = bv[cidx[i]];

  free(cidx);
  Py_DECREF(aa);
  Py_DECREF(ba);
  
  return Py_BuildValue("N", ca);
}


static PyObject *misc_is_power(PyObject *self, PyObject *args, PyObject *keywds)
{
  PyObject *ret;
  int n, b;
    
  static char *kwlist[] = {"n", "b", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, keywds, "ii", kwlist, &n, &b))
    return NULL;
  
  if (is_power(n, b)) ret = Py_True;
  else ret = Py_False;
  
  return Py_BuildValue("N", ret);
}


static PyObject *misc_next_power(PyObject *self, PyObject *args, PyObject *keywds)
{
  int n, b;
  int ret;
    
  static char *kwlist[] = {"n", "b", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, keywds, "ii", kwlist, &n, &b))
    return NULL;
  
  if ((b == 0) && (n != 1))
    return Py_BuildValue("N", Py_None);
  else
    {
      if (n <= 0)
	ret = 0;
      else
	ret = n;
      
      while (!is_power(ret, b))
	ret++;
      
      return Py_BuildValue("i", ret);
    }
}


static char module_doc[] = "Misc";

static char misc_away_doc[] =
  "Given numpy 1D array *a* and numpy 1D array *b*\n"
  "compute *c* = { bi : | bi - aj | > d for each i, j} \n\n"
  "Input\n\n"
  "  * *a* - [1D numpy array float]\n"
  "  * *b* - [1D numpy array float]\n"
  "  * *d* - [double]\n\n"
  "Output\n\n"
  "  * *c* - [1D numpy array float]"
  ;


static char misc_is_power_doc[] =
  "Return True if 'n' is power of 'b', False otherwise."
  ;


static char misc_next_power_doc[] =
  "Returns the smallest integer, greater than or equal to 'n'\n"
  "which can be obtained as power of 'b'."
  ;


/* Method table */
static PyMethodDef misc_methods[] = {
  {"away",
   (PyCFunction)misc_away,
   METH_VARARGS | METH_KEYWORDS,
   misc_away_doc},
  {"is_power",
   (PyCFunction)misc_is_power,
   METH_VARARGS | METH_KEYWORDS,
   misc_is_power_doc},
  {"next_power",
   (PyCFunction)misc_next_power,
   METH_VARARGS | METH_KEYWORDS,
   misc_next_power_doc},
  {NULL, NULL, 0, NULL}
};


/* Init */
void initmisc()
{
  Py_InitModule3("misc", misc_methods, module_doc);
  import_array();
}
