/*
 * call-seq:
 * Mod.new(mod_type, attr, vals)  => LDAP::Mod
 *
 * Create a new LDAP::Mod object of type +mod_type+. This is most commonly
 * *LDAP_MOD_ADD*, *LDAP_MOD_REPLACE* or *LDAP_MOD_DELETE*, although some LDAP
 * servers may offer extension types. 
 *
 * +attr+ should be the name of the attribute on which to operate, whilst
 * +vals+ is an array of values pertaining to +attr+. If +vals+ contains
 * binary data, +mod_type+ should be logically OR'ed (|) with
 * *LDAP_MOD_BVALUES*.
 *
 * LDAP::Mod objects can be passed to methods in the LDAP::Conn class, such as
 * Conn#add, Conn#add_ext, Conn#modify and Conn#modify_ext.
 */
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;
}