/*
  narray.c

  Written by Yoshiki Tsunesada       Dec/2001
  Modified by Seiya Nishizawa        14/Apr/2004
 */

#include "rb_gsl_config.h"
#ifdef HAVE_NARRAY_H
#include "rb_gsl_array.h"
#include "narray.h"
#include "rb_gsl_with_narray.h"

static VALUE rb_gsl_na_to_gsl_matrix_method(VALUE nna);
static VALUE rb_gsl_na_to_gsl_matrix_int_method(VALUE nna);
static VALUE rb_gsl_na_to_gsl_vector_int_method(VALUE na);
static VALUE rb_gsl_vector_int_to_na(VALUE obj);
static VALUE rb_gsl_na_to_gsl_vector_int(VALUE obj, VALUE na);

/* GSL::Vector -> NArray */
static VALUE rb_gsl_vector_to_na(VALUE obj)
{
  gsl_vector *v = NULL;
  VALUE nary;
  int shape[1];
  Data_Get_Struct(obj, gsl_vector, v);
  shape[0] = v->size;
  nary = na_make_object(NA_DFLOAT, 1, shape, cNArray);
  memcpy(NA_PTR_TYPE(nary,double*), v->data, shape[0]*sizeof(double));
  return nary;
}

static VALUE rb_gsl_vector_int_to_na(VALUE obj)
{
  gsl_vector_int *v = NULL;
  VALUE nary;
  int shape[1];
  Data_Get_Struct(obj, gsl_vector_int, v);
  shape[0] = v->size;
  nary = na_make_object(NA_LINT, 1, shape, cNArray);
  memcpy(NA_PTR_TYPE(nary,int*), v->data, shape[0]*sizeof(int));
  return nary;
}

/* singleton method */
static VALUE rb_gsl_na_to_gsl_vector(VALUE obj, VALUE na)
{
  return Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free,
			  na_to_gv(na));
}

static VALUE rb_gsl_na_to_gsl_vector_view(VALUE obj, VALUE na)
{
  return Data_Wrap_Struct(cgsl_vector_view, 0, gsl_vector_view_free,
			  na_to_gv_view(na));
}

static VALUE rb_gsl_na_to_gsl_vector_int(VALUE obj, VALUE na)
{
  return Data_Wrap_Struct(cgsl_vector_int, 0, gsl_vector_int_free,
			  na_to_gv_int(na));
}

static VALUE rb_gsl_na_to_gsl_vector_int_view(VALUE obj, VALUE na)
{
  return Data_Wrap_Struct(cgsl_vector_int_view, 0, rb_gsl_vector_int_view_free,
			  na_to_gv_int_view(na));
}

static VALUE rb_gsl_na_to_gsl_vector_method(VALUE na)
{
  return Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free,
			  na_to_gv(na));
}

static VALUE rb_gsl_na_to_gsl_vector_view_method(VALUE na)
{
  return Data_Wrap_Struct(cgsl_vector_view, 0, gsl_vector_view_free,
			  na_to_gv_view(na));
}

static VALUE rb_gsl_na_to_gsl_vector_int_method(VALUE na)
{
  return Data_Wrap_Struct(cgsl_vector_int, 0, gsl_vector_int_free,
			  na_to_gv_int(na));
}

static VALUE rb_gsl_na_to_gsl_vector_int_view_method(VALUE na)
{
  return Data_Wrap_Struct(cgsl_vector_int_view, 0, rb_gsl_vector_int_view_free,
			  na_to_gv_int_view(na));
}

gsl_vector* na_to_gv(VALUE na)
{
  gsl_vector *v = NULL;
  VALUE nary;
  v = gsl_vector_alloc(NA_TOTAL(na));
  nary = na_change_type(na, NA_DFLOAT);
  memcpy(v->data, NA_PTR_TYPE(nary,double*), v->size*sizeof(double));
  return v;
}

gsl_vector_view* na_to_gv_view(VALUE na)
{
  gsl_vector_view *v = NULL;
  VALUE ary2;
  v = gsl_vector_view_alloc();
  ary2 = na_change_type(na, NA_DFLOAT);
  v->vector.data = NA_PTR_TYPE(ary2,double*);
  v->vector.size = NA_TOTAL(na);
  v->vector.stride = 1;
  v->vector.owner = 0;
  return v;
}

gsl_vector_int* na_to_gv_int(VALUE na)
{
  gsl_vector_int *v = NULL;
  VALUE nary;
  v = gsl_vector_int_alloc(NA_TOTAL(na));
  nary = na_change_type(na, NA_LINT);
  memcpy(v->data, NA_PTR_TYPE(nary,int*), v->size*sizeof(int));
  return v;
}

gsl_vector_int_view* na_to_gv_int_view(VALUE na)
{
  gsl_vector_int_view *v = NULL;
  VALUE ary2;
  v = rb_gsl_vector_int_view_alloc(NA_TOTAL(na));
  ary2 = na_change_type(na, NA_LINT);
  v->vector.data = NA_PTR_TYPE(ary2,int*);
  v->vector.size = NA_TOTAL(na);
  v->vector.stride = 1;
  v->vector.owner = 0;
  return v;
}

static VALUE rb_gsl_matrix_to_na(VALUE obj)
{
  gsl_matrix *m = NULL;
  gsl_vector_view vv;
  VALUE ary;
  size_t i, size;
  Data_Get_Struct(obj, gsl_matrix, m);
  size = m->size1;
  ary = rb_ary_new2(size);
  for (i = 0; i < size; i++) {
    vv = gsl_matrix_row(m, i);
    rb_ary_store(ary, i, make_rarray_from_cvector(&vv.vector));
  }
  return na_ary_to_nary(ary, cNArray);
}

static VALUE rb_gsl_matrix_int_to_na(VALUE obj)
{
  gsl_matrix_int *m = NULL;
  gsl_vector_int_view vv;
  VALUE ary;
  size_t i, size;
  Data_Get_Struct(obj, gsl_matrix_int, m);
  size = m->size1;
  ary = rb_ary_new2(size);
  for (i = 0; i < size; i++) {
    vv = gsl_matrix_int_row(m, i);
    rb_ary_store(ary, i, make_rarray_from_cvector_int(&vv.vector));
  }
  return na_ary_to_nary(ary, cNArray);
}

/* NArray -> GSL::Matrix */
VALUE rb_gsl_na_to_gsl_matrix(VALUE obj, VALUE nna)
{
  gsl_matrix *m = NULL;
  m = na_to_gm(nna);
  return Data_Wrap_Struct(cgsl_matrix, 0, gsl_matrix_free, m);
}

VALUE rb_gsl_na_to_gsl_matrix_view(VALUE obj, VALUE nna)
{
  gsl_matrix_view *m = NULL;
  m = na_to_gm_view(nna);
  return Data_Wrap_Struct(cgsl_matrix_view, 0, gsl_matrix_view_free, m);
}

VALUE rb_gsl_na_to_gsl_matrix_int(VALUE obj, VALUE nna)
{
  gsl_matrix_int *m = NULL;
  m = na_to_gm_int(nna);
  return Data_Wrap_Struct(cgsl_matrix_int, 0, gsl_matrix_int_free, m);
}

VALUE rb_gsl_na_to_gsl_matrix_int_view(VALUE obj, VALUE nna)
{
  gsl_matrix_int_view *m = NULL;
  m = na_to_gm_int_view(nna);
  return Data_Wrap_Struct(cgsl_matrix_int_view, 0, rb_gsl_matrix_int_view_free, m);
}

static VALUE rb_gsl_na_to_gsl_matrix_method(VALUE nna)
{
  gsl_matrix *m = NULL;
  m = na_to_gm(nna);
  return Data_Wrap_Struct(cgsl_matrix, 0, gsl_matrix_free, m);
}

static VALUE rb_gsl_na_to_gsl_matrix_view_method(VALUE nna)
{
  gsl_matrix_view *m = NULL;
  m = na_to_gm_view(nna);
  return Data_Wrap_Struct(cgsl_matrix_view, 0, gsl_matrix_view_free, m);
}

static VALUE rb_gsl_na_to_gsl_matrix_int_method(VALUE nna)
{
  gsl_matrix_int *m = NULL;
  m = na_to_gm_int(nna);
  return Data_Wrap_Struct(cgsl_matrix_int, 0, gsl_matrix_int_free, m);
}

static VALUE rb_gsl_na_to_gsl_matrix_int_view_method(VALUE nna)
{
  gsl_matrix_int_view *m = NULL;
  m = na_to_gm_int_view(nna);
  return Data_Wrap_Struct(cgsl_matrix_int_view, 0, rb_gsl_matrix_int_view_free, m);
}

gsl_matrix* na_to_gm(VALUE nna)
{
  gsl_matrix *m = NULL;
  VALUE ary2;
  struct NARRAY *na = NULL;
  GetNArray(nna, na);
  m = gsl_matrix_alloc(na->shape[1], na->shape[0]);
  ary2 = na_change_type(nna, NA_DFLOAT);
  memcpy(m->data, NA_PTR_TYPE(ary2,double*), m->size1*m->size2*sizeof(double));
  return m;
}

gsl_matrix_view* na_to_gm_view(VALUE nna)
{
  gsl_matrix_view *m = NULL;
  VALUE ary2;
  struct NARRAY *na = NULL;
  GetNArray(nna, na);
  m = gsl_matrix_view_alloc();
  ary2 = na_change_type(nna, NA_DFLOAT);
  m->matrix.data = NA_PTR_TYPE(ary2,double*);
  m->matrix.size1 = na->shape[1];
  m->matrix.size2 = na->shape[0];
  m->matrix.tda = m->matrix.size2; 
  m->matrix.owner = 0;
  return m;
}

gsl_matrix_int* na_to_gm_int(VALUE nna)
{
  gsl_matrix_int *m = NULL;
  VALUE ary2;
  struct NARRAY *na = NULL;
  GetNArray(nna, na);
  m = gsl_matrix_int_alloc(na->shape[1], na->shape[0]);
  ary2 = na_change_type(nna, NA_LINT);
  memcpy(m->data, NA_PTR_TYPE(ary2,int*), m->size1*m->size2*sizeof(int));
  return m;
}

gsl_matrix_int_view* na_to_gm_int_view(VALUE nna)
{
  gsl_matrix_int_view *m = NULL;
  VALUE ary2;
  struct NARRAY *na = NULL;
  GetNArray(nna, na);
  m = rb_gsl_matrix_int_view_alloc(na->shape[1], na->shape[0]);
  ary2 = na_change_type(nna, NA_LINT);
  m->matrix.data = NA_PTR_TYPE(ary2,int*);
  m->matrix.size1 = na->shape[1];
  m->matrix.size2 = na->shape[0];
  m->matrix.tda = m->matrix.size2; 
  m->matrix.owner = 0;
  return m;
}

/*void rb_gsl_with_narray_define_methods()*/
void Init_gsl_narray(VALUE module)
{
  rb_define_method(cgsl_vector, "to_na", rb_gsl_vector_to_na, 0);

  rb_define_singleton_method(cgsl_vector, "to_gslv", rb_gsl_na_to_gsl_vector, 1);
  rb_define_singleton_method(cgsl_vector, "to_gv", rb_gsl_na_to_gsl_vector, 1);

  rb_define_singleton_method(cgsl_vector, "na_to_gslv", rb_gsl_na_to_gsl_vector, 1);
  rb_define_singleton_method(cgsl_vector, "na_to_gv", rb_gsl_na_to_gsl_vector, 1);
  rb_define_singleton_method(cgsl_vector, "to_gslv_view", rb_gsl_na_to_gsl_vector_view, 1);

  rb_define_singleton_method(cgsl_vector, "to_gv_view", rb_gsl_na_to_gsl_vector_view, 1);

  rb_define_singleton_method(cgsl_vector, "na_to_gslv_view", rb_gsl_na_to_gsl_vector_view, 1);
  rb_define_singleton_method(cgsl_vector, "na_to_gv_view", rb_gsl_na_to_gsl_vector, 1);

  rb_define_method(cNArray, "to_gv", rb_gsl_na_to_gsl_vector_method, 0);
  rb_define_alias(cNArray, "to_gslv", "to_gv");
  rb_define_method(cNArray, "to_gv_view", rb_gsl_na_to_gsl_vector_view_method, 0);  rb_define_alias(cNArray, "to_gslv_view", "to_gv_view");
  /*****/
  rb_define_method(cgsl_vector_int, "to_na", rb_gsl_vector_int_to_na, 0);


  rb_define_singleton_method(cgsl_vector_int, "to_gslv", rb_gsl_na_to_gsl_vector_int, 1);
  rb_define_singleton_method(cgsl_vector_int, "to_gv", rb_gsl_na_to_gsl_vector_int, 1);

  rb_define_singleton_method(cgsl_vector_int, "na_to_gslv", rb_gsl_na_to_gsl_vector_int, 1);
  rb_define_singleton_method(cgsl_vector_int, "na_to_gv", rb_gsl_na_to_gsl_vector_int, 1);

  rb_define_singleton_method(cgsl_vector_int, "to_gslv_view", rb_gsl_na_to_gsl_vector_int_view, 1);
  rb_define_singleton_method(cgsl_vector_int, "to_gv_view", rb_gsl_na_to_gsl_vector_int_view, 1);

  rb_define_singleton_method(cgsl_vector_int, "na_to_gslv_view", rb_gsl_na_to_gsl_vector_int, 1);
  rb_define_singleton_method(cgsl_vector_int, "na_to_gv_view", rb_gsl_na_to_gsl_vector_int_view, 1);

  rb_define_method(cNArray, "to_gv_int", rb_gsl_na_to_gsl_vector_int_method, 0);
  rb_define_alias(cNArray, "to_gslv_int", "to_gv_int");
  rb_define_method(cNArray, "to_gv_int_view", rb_gsl_na_to_gsl_vector_int_view_method, 0);
  rb_define_alias(cNArray, "to_gslv_int_view", "to_gv_int_view");
  /*****/

  rb_define_method(cgsl_matrix, "to_na", rb_gsl_matrix_to_na, 0);

  rb_define_singleton_method(cgsl_matrix, "to_gslm", rb_gsl_na_to_gsl_matrix, 1);
  rb_define_singleton_method(cgsl_matrix, "to_gm", rb_gsl_na_to_gsl_matrix, 1);

  rb_define_singleton_method(cgsl_matrix, "na_to_gslm", rb_gsl_na_to_gsl_matrix, 1);
  rb_define_singleton_method(cgsl_matrix, "na_to_gm", rb_gsl_na_to_gsl_matrix, 1);

  rb_define_singleton_method(cgsl_matrix, "to_gslm_view", rb_gsl_na_to_gsl_matrix_view, 1);
  rb_define_singleton_method(cgsl_matrix, "to_gm_view", rb_gsl_na_to_gsl_matrix_view, 1);

  rb_define_singleton_method(cgsl_matrix, "na_to_gslm_view", rb_gsl_na_to_gsl_matrix_view, 1);
  rb_define_singleton_method(cgsl_matrix, "na_to_gm_view", rb_gsl_na_to_gsl_matrix_view, 1);

  rb_define_method(cNArray, "to_gm", rb_gsl_na_to_gsl_matrix_method, 0);
  rb_define_method(cNArray, "to_gm_view", rb_gsl_na_to_gsl_matrix_view_method, 0);

  /*****/
  rb_define_method(cgsl_matrix_int, "to_na", rb_gsl_matrix_int_to_na, 0);


  rb_define_singleton_method(cgsl_matrix_int, "to_gslm", rb_gsl_na_to_gsl_matrix_int, 1);
  rb_define_singleton_method(cgsl_matrix_int, "to_gm", rb_gsl_na_to_gsl_matrix_int, 1);
  rb_define_singleton_method(cgsl_matrix_int, "na_to_gslm", rb_gsl_na_to_gsl_matrix_int, 1);
  rb_define_singleton_method(cgsl_matrix_int, "na_to_gm", rb_gsl_na_to_gsl_matrix_int, 1);

  rb_define_singleton_method(cgsl_matrix_int, "to_gslm_view", rb_gsl_na_to_gsl_matrix_int_view, 1);
  rb_define_singleton_method(cgsl_matrix_int, "to_gm_view", rb_gsl_na_to_gsl_matrix_int_view, 1);
  rb_define_singleton_method(cgsl_matrix_int, "na_to_gslm_view", rb_gsl_na_to_gsl_matrix_int_view, 1);
  rb_define_singleton_method(cgsl_matrix_int, "na_to_gm_view", rb_gsl_na_to_gsl_matrix_int_view, 1);

  rb_define_method(cNArray, "to_gm_int", rb_gsl_na_to_gsl_matrix_int_method, 0);
  rb_define_alias(cNArray, "to_gslm_int", "to_gm_int");
  rb_define_method(cNArray, "to_gm_int_view", rb_gsl_na_to_gsl_matrix_int_view_method, 0);
  rb_define_alias(cNArray, "to_gslm_int_view", "to_gm_int_view");
}

#endif
