/*
 * mod.c
 * $Id: mod.c,v 1.4 2003/11/16 04:55:14 ttate Exp $
 */

#include "ruby.h"
#include "rbldap.h"

VALUE rb_cLDAP_Mod;


void
rb_ldap_mod_free(RB_LDAPMOD_DATA *data)
{
  if( data->mod ){
    struct berval **bvals;
    char **svals;
    int i;

    if( data->mod->mod_op & LDAP_MOD_BVALUES ){
      bvals =data->mod->mod_vals.modv_bvals;
      for( i=0; bvals[i] != NULL; i++ ){
	xfree(bvals[i]);
      }
      xfree(bvals);
    }
    else{
      svals = data->mod->mod_vals.modv_strvals;
      for( i=0; svals[i] != NULL; i++ ){
	xfree(svals[i]);
      }
      xfree(svals);
    }
    xfree(data->mod);
  }
}

static LDAPMod*
rb_ldap_new_mod(int mod_op, char *mod_type, char **modv_strvals)
{
  LDAPMod *mod;

  if( mod_op & LDAP_MOD_BVALUES ){
    rb_bug("rb_ldap_mod_new: illegal mod_op");
  }

  mod = ALLOC_N(LDAPMod, 1);
  mod->mod_op = mod_op;
  mod->mod_type = mod_type;
  mod->mod_vals.modv_strvals = modv_strvals;

  return mod;
}

VALUE
rb_ldap_mod_new(int mod_op, char *mod_type, char **modv_strvals)
{
  VALUE obj;
  RB_LDAPMOD_DATA *moddata;

  obj = Data_Make_Struct(rb_cLDAP_Mod, RB_LDAPMOD_DATA,
			 0, rb_ldap_mod_free, moddata);
  moddata->mod = rb_ldap_new_mod(mod_op, mod_type, modv_strvals);

  return obj;
}

static LDAPMod*
rb_ldap_new_mod2(int mod_op, char *mod_type, struct berval **modv_bvals)
{
  LDAPMod *mod;

  if( !(mod_op & LDAP_MOD_BVALUES) ){
    rb_bug("rb_ldap_mod_new: illegal mod_op");
  }

  mod = ALLOC_N(LDAPMod, 1);
  mod->mod_op = mod_op;
  mod->mod_type = mod_type;
  mod->mod_vals.modv_bvals = modv_bvals;

  return mod;
}

VALUE
rb_ldap_mod_new2(int mod_op, char *mod_type, struct berval **modv_bvals)
{
  VALUE obj;
  RB_LDAPMOD_DATA *moddata;

  obj = Data_Make_Struct(rb_cLDAP_Mod, RB_LDAPMOD_DATA,
			 0, rb_ldap_mod_free, moddata);
  moddata->mod = rb_ldap_new_mod2(mod_op, mod_type, modv_bvals);

  return obj;
}

static VALUE
rb_ldap_mod_s_allocate(VALUE klass)
{
  RB_LDAPMOD_DATA *moddata;
  VALUE obj;

  obj = Data_Make_Struct(klass, RB_LDAPMOD_DATA, 0, rb_ldap_mod_free, moddata);
  moddata->mod = NULL;

  return obj;
}

static VALUE
rb_ldap_mod_initialize(int argc, VALUE argv[], VALUE self)
{
  struct berval **bvals;
  char **strvals;
  int mod_op;
  char *mod_type;
  int i;
  VALUE op, type, vals;
  RB_LDAPMOD_DATA *moddata;

  rb_scan_args(argc, argv, "3", &op, &type, &vals);
  Data_Get_Struct(self, RB_LDAPMOD_DATA, moddata);
  if( moddata->mod )
    return Qnil;

  mod_op = NUM2INT(op);
  mod_type = StringValueCStr(type);
  Check_Type(vals, T_ARRAY);

  if( mod_op & LDAP_MOD_BVALUES ){
    bvals = ALLOC_N(struct berval *, RARRAY(vals)->len + 1);
    for( i=0; i < RARRAY(vals)->len; i++ ){
      VALUE str;
      struct berval *bval;
      str = RARRAY(vals)->ptr[i];
      Check_Type(str, T_STRING);
      bval = ALLOC_N(struct berval, 1);
      bval->bv_len = RSTRING(str)->len;
      RB_LDAP_SET_STR(bval->bv_val, str);
      bvals[i] = bval;
    }
    bvals[i] = NULL;
    moddata->mod = rb_ldap_new_mod2(mod_op, mod_type, bvals);
  }
  else{
    strvals = ALLOC_N(char*, RARRAY(vals)->len + 1);
    for( i=0; i < RARRAY(vals)->len; i++ ){
      VALUE str;
      char *sval;
      str = RARRAY(vals)->ptr[i];
      RB_LDAP_SET_STR(sval, str);
      strvals[i] = sval;
    }
    strvals[i] = NULL;
    moddata->mod = rb_ldap_new_mod(mod_op, mod_type, strvals);
  }

  return Qnil;
}

VALUE
rb_ldap_mod_op(VALUE self)
{
  RB_LDAPMOD_DATA *moddata;

  GET_LDAPMOD_DATA(self, moddata);
  return INT2NUM(moddata->mod->mod_op);
}

VALUE
rb_ldap_mod_type(VALUE self)
{
  RB_LDAPMOD_DATA *moddata;

  GET_LDAPMOD_DATA(self, moddata);
  return rb_tainted_str_new2(moddata->mod->mod_type);
}

VALUE
rb_ldap_mod_vals(VALUE self)
{
  RB_LDAPMOD_DATA *moddata;
  struct berval **bvals;
  char **svals;
  int i;
  VALUE val;

  GET_LDAPMOD_DATA(self, moddata);

  if( moddata->mod->mod_op & LDAP_MOD_BVALUES ){
    bvals = moddata->mod->mod_vals.modv_bvals;
    val = rb_ary_new();
    for( i = 0; bvals[i] != NULL; i++ ){
      VALUE str;
      str = rb_tainted_str_new(bvals[i]->bv_val, bvals[i]->bv_len);
      rb_ary_push(val, str);
    }
  }
  else{
    svals = moddata->mod->mod_vals.modv_strvals;
    val = rb_ary_new();
    for( i = 0; svals[i] != NULL; i++ ){
      VALUE str;
      str = rb_tainted_str_new2(svals[i]);
      rb_ary_push(val, str);
    }
  }

  return val;
}

void
Init_ldap_mod(){
  rb_cLDAP_Mod = rb_define_class_under(rb_mLDAP,"Mod",rb_cObject);
#if RUBY_VERSION_CODE < 170
  rb_define_singleton_method(rb_cLDAP_Mod, "new", rb_ldap_class_new, -1);
#endif
#if RUBY_VERSION_CODE >= 173
  rb_define_alloc_func(rb_cLDAP_Mod, rb_ldap_mod_s_allocate);
#else
  rb_define_singleton_method(rb_cLDAP_Mod, "allocate", rb_ldap_mod_s_allocate,0);
#endif
  rb_ldap_mod_define_method("initialize", rb_ldap_mod_initialize, -1);
  rb_ldap_mod_define_method("mod_op", rb_ldap_mod_op, 0);
  rb_ldap_mod_define_method("mod_type", rb_ldap_mod_type, 0);
  rb_ldap_mod_define_method("mod_vals", rb_ldap_mod_vals, 0);

  /*
  rb_ldap_mod_define_method("mod_op=", rb_ldap_mod_set_op, 1);
  rb_ldap_mod_define_method("mod_type=", rb_ldap_mod_set_type, 1);
  rb_ldap_mod_define_method("mod_vals=", rb_ldap_mod_set_vals, 1);
  */
}
