#include<stdio.h>
#include<hdf5.h>
#include<HE5_HdfEosDef.h>
#include "ruby.h"
#include "narray.h"
#include<string.h>

#ifndef RSTRING_PTR
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
#endif
#ifndef SafeStringValue
#define SafeStringValue(s) Check_SafeStr(s)
#endif

VALUE rb_eHE5Error;
VALUE cHE5;

static VALUE mNumRu;

void init_hdfeos5sw_wrap(void);
void init_hdfeos5gd_wrap(void);
void init_hdfeos5za_wrap(void);
void init_hdfeos5pt_wrap(void);

struct HE5{
  hid_t fid;
  char *name;
  int closed;
};

void
HE5_free(struct HE5 *HE5file)
{
  int status;
  if (!HE5file->closed){
      status = HE5_EHclose(HE5file->fid);
  }
  free(HE5file->name);
  free(HE5file);
}

static struct HE5 *
HE5_init(hid_t fid, char *name)
{
  struct HE5 *HE5file;
  HE5file=xmalloc(sizeof(struct HE5));
  HE5file->fid=fid;
  HE5file->name=xmalloc((strlen(name)+1)*sizeof(char));
  strcpy(HE5file->name,name);
  HE5file->closed=0;
  return(HE5file);
}

VALUE
HE5_clone(VALUE file)
{
    VALUE clone;
    struct HE5 *he51, *he52;

    Data_Get_Struct(file, struct HE5, he51);
    he52 = HE5_init(he51->fid, he51->name);
    clone = Data_Wrap_Struct(cHE5, 0, HE5_free, he52);
    CLONESETUP(clone, file);
    return clone;
}


VALUE
hdfeos5_ehopen(VALUE mod, VALUE filename, VALUE flags)
{
    char *i_filename;
    char *i_flags;
    uintn c_flags;
    hid_t fid;
    struct HE5 *he5file;

    Check_Type(filename,T_STRING);
    SafeStringValue(filename);
    Check_Type(flags,T_STRING);
    SafeStringValue(flags);

    i_filename  = RSTRING_PTR(filename);
    i_flags     = RSTRING_PTR(flags);

    if(strcmp(i_flags,"H5F_ACC_TRUNC")==0) c_flags = H5F_ACC_TRUNC;
    if(strcmp(i_flags,"H5F_ACC_RDWR")==0)  c_flags = H5F_ACC_RDWR;
    if(strcmp(i_flags,"H5F_ACC_CREAT")==0) c_flags = H5F_ACC_CREAT;
    if(strcmp(i_flags,"H5F_ACC_RDONLY")==0)  c_flags = H5F_ACC_RDONLY;

    fid  = HE5_EHopen(i_filename, c_flags, H5P_DEFAULT);
    he5file = HE5_init(fid, i_filename);

    return (Data_Wrap_Struct(cHE5,0,HE5_free,he5file));
}

VALUE
hdfeos5_path(VALUE file)
{
    char *i_name;
    struct HE5 *he5file;

    rb_secure(4);
    Data_Get_Struct(file, struct HE5, he5file);
    i_name=he5file->name;

    return rb_str_new2(i_name);
}

VALUE
hdfeos5_close(VALUE file)
{
    hid_t i_fid;
    herr_t o_rtn_val;
    struct HE5 *he5file;

    if (rb_safe_level() >= 4 && !OBJ_TAINTED(file)) {
      rb_raise(rb_eSecurityError, "Insecure: can't close [%s:%d]",__FILE__,__LINE__);
    }
    Data_Get_Struct(file, struct HE5, he5file);
    i_fid=he5file->fid;

    if(!he5file->closed){
      o_rtn_val = HE5_EHclose(i_fid);
      if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
      he5file->closed = 1;
    } else {
      rb_warn("file %s is already closed", he5file->name);
    }
    return Qnil;
}

void
Init_hdfeos5raw(void)
{
    /* Difinitions of the classes */;
    mNumRu = rb_define_module("NumRu");
    cHE5 = rb_define_class_under(mNumRu, "HE5",rb_cObject);
    rb_eHE5Error = rb_define_class("HE5Error",rb_eStandardError);

    /* Class Constants Definition */
    /* Difinitions of the HE5 Class */;
    rb_define_singleton_method(cHE5, "he5_open", hdfeos5_ehopen, 2);
    rb_define_method(cHE5, "close", hdfeos5_close, 0);
    /* Original of the HE5 Class */;
    rb_define_method(cHE5, "path", hdfeos5_path, 0);

    init_hdfeos5sw_wrap();
    init_hdfeos5gd_wrap();
    init_hdfeos5za_wrap();
    init_hdfeos5pt_wrap();

}
