/*
 * access to grid information
 *
 * grid(type1, type2, type3, basetime, member, validtime, "get")
 *  arguments:
 *   type1, type2, type3, member: String
 *   basetime, validtime: Integer (minuits from 00:00 1 Jan 1801)
 *  return:
 *   projection: String
 *   gridsize: Array[2] (nx,ny)
 *   gridinfo: Array[14] (basepoint_x, basepoint_y, basepoint_lat, basepoint_lon, distance_x, distance_y, standard_lat, standard_lon, standard2_lat, standard2_lon, other_lat, other_lon, other2_lat, other2_lon)
 *   value: String
 *
 * grid(type1, type2, type3, basetime, member, validtime, "put", projection, gridsize, gridinfo, value)
 *  arguments:
 *   type1, type2, type3, member: String
 *   basetime, validtime: Integer (minuits from 00:00 1 Jan 1801)
 *   projection: String
 *   gridsize: Array[2] (nx,ny)
 *   gridinfo: Array[14] (basepoint_x, basepoint_y, basepoint_lat, basepoint_lon, distance_x, distance_y, standard_lat, standard_lon, standard2_lat, standard2_lon, other_lat, other_lon, other2_lat, other2_lon)
 *   value: String
 *  return:
 *   nil
 */
VALUE
rb_grid(int argc, VALUE *argv, VALUE self)
{
  VALUE type1, type2, type3;
  VALUE basetime, member, validtime;
  VALUE getput;
  VALUE proj, gridsize, gridinfo, value;

  char cproj[3], cvalue[5];
  N_SI4 cgridsize[2];
  float cgridinfo[14];

  struct NARRAY* nary;
  VALUE* ary;
  int16_t *cary_sint;
  float *cary_float;
  int flag=0;
  int i;
  N_SI4 code;

  rb_scan_args(argc, argv, "74",
               &type1, &type2, &type3,
               &basetime, &member, &validtime,
               &getput,
               &proj, &gridsize, &gridinfo, &value);

  GetChar(getput,3);
  if (strcmp(cgetput,"get") || strcmp(cgetput,"GET")) {
    if (argc != 7)
      rb_raise(rb_eArgError, "wrong number of arguments for get (%d for 7)", argc);
    flag = 1;
  } else if (strcmp(cgetput,"put") || strcmp(cgetput,"PUT")) {
    if (argc != 11)
      rb_raise(rb_eArgError, "wrong number of arguments for put (%d for 11)", argc);
    if (TYPE(gridsize)==T_ARRAY) {
      if (RARRAY_LEN(gridsize)!=2)
        rb_raise(rb_eArgError, "length of gridsize must be 2");
      ary = RARRAY_PTR(gridsize);
      for (i=0;i<2;i++)
        cgridsize[i] = NUM2INT(ary[i]);
    } else if (IsNArray(gridsize)){
      if (NA_TOTAL(gridsize)!=2)
        rb_raise(rb_eArgError, "length of gridsize must be 2");
      gridsize = na_cast_object(gridsize, NA_SINT);
      GetNArray(gridsize,nary);
      cary_sint = NA_PTR_TYPE(nary,int16_t*);
      for (i=0;i<2;i++)
        cgridsize[i] = (N_SI4)cary_sint[i];
    } else
      rb_raise(rb_eArgError, "gridsize must be NArray of Array");

    if (TYPE(gridinfo)==T_ARRAY) {
      if (RARRAY_LEN(gridinfo)!=14)
        rb_raise(rb_eArgError, "length of gridsize must be 14");
      ary = RARRAY_PTR(gridinfo);
      for (i=0;i<14;i++)
        cgridinfo[i] = (float)NUM2DBL(ary[i]);
    } else if (IsNArray(gridinfo)){
      if (NA_TOTAL(gridinfo)!=14)
        rb_raise(rb_eArgError, "length of gridinfo must be 14");
      gridinfo = na_cast_object(gridinfo, NA_SFLOAT);
      GetNArray(gridinfo,nary);
      cary_float = NA_PTR_TYPE(nary,float*);
      for (i=0;i<14;i++)
        cgridinfo[i] = cary_float[i];
    } else
      rb_raise(rb_eArgError, "gridinfo must be NArray of Array");

    GetCharUndef(proj, 3);
    GetCharUndef(value, 4);
  }

  GetTypes;
  GetTimesAndMember;

  code = nusdas_grid(ctype1, ctype2, ctype3,
                     &cbasetime, cmember, &cvalidtime,
                     cproj, cgridsize, cgridinfo, cvalue,
                     cgetput);

  if (code == -5)
    rb_raise(rb_eRuntimeError, "getput is invalid");
  else if (code != 0)
    rb_raise(rb_eRuntimeError, "faild: code=%d", code);

  if ( flag==1 ) {
    proj = rb_str_new(cproj,4);
    gridsize = rb_ary_new();
    for(i=0;i<2;i++)
      rb_ary_push(gridsize, INT2NUM((int)cgridsize[i]));
    gridinfo = rb_ary_new();
    for(i=0;i<14;i++)
      rb_ary_push(gridinfo, rb_float_new((double)cgridinfo[i]));
    value = rb_str_new(cvalue,4);
    return rb_ary_new3(4, proj, gridsize, gridinfo, value);
  } else
    return Qnil;
}