library ini;

uses SysUtils, Classes, IniFiles, Rubies, uDefUtils, Pythia;

{$E so}

var
  mIni, cIniFile: Tvalue;

function IniFile_new(This, v: Tvalue): Tvalue; cdecl;
var
  real: TIniFile;
  fname: string;
begin
  fname := dl_String(v);
  real := TIniFile.Create(fname);
  result := ObjAlloc(This, real);
  rb_iv_set(result, '@file_name', v);
  ap_obj_call_init(result, 1, @v);
end;

function IniFile_aref(argc: integer; argv: Pointer; This: Tvalue): Tvalue; cdecl;
var
  args: array of Tvalue;
  real: TIniFile;
  sec, ent, str: string;
  strings: TStrings;
begin
  if argc < 1 then ap_raise(ap_eArgError, sToo_few_args);
  SetLength(args, argc);
  args := argv;
  real := ap_data_get_struct(This);
  case RTYPE(args[0]) of
  T_STRING:
    begin
      sec := dl_String(args[0]);
      if argc > 1 then
      begin
        case RTYPE(args[1]) of
        T_STRING:
          begin
            ent := dl_String(args[1]);
            if argc > 2 then
            begin
              case RTYPE(args[2]) of
              T_STRING:
                begin
                  str := dl_String(args[2]);
                  result := rb_str_new2(PChar(real.ReadString(sec, ent, str)));
                  Exit;
                end;
              else
                ap_raise(ap_eArgError, sWrong_arg_type);
              end;
            end;
          end;
        T_DATA:
          begin
            ap_data_get_object(args[1], TStrings, strings);
            real.ReadSectionValues(sec, strings);
          end;
        else
          ap_raise(ap_eArgError, sWrong_arg_type)
        end;
      end;
    end;
  T_DATA:
    begin
      ap_data_get_object(args[0], TStrings, strings);
      real.ReadSections(strings);
    end;
  else
  end;
  result := args[argc-1];
end;

function IniFile_aset(argc: integer; argv: Pointer; This: Tvalue): Tvalue; cdecl;
var
  args: array of Tvalue;
  real: TIniFile;
  sec, ent, str: string;
begin
  if argc < 3 then ap_raise(ap_eArgError, sToo_few_args);
  SetLength(args, argc);
  args := argv;
  real := ap_data_get_struct(This);
  sec := dl_String(args[0]);
  ent := dl_String(args[1]);
  str := dl_String(args[2]);
  real.WriteString(sec, ent, str);
  result := args[argc-1];
end;

function IniFile_exist_p(argc: integer; argv: Pointer; This: Tvalue): Tvalue; cdecl;
var
  args: array of Tvalue;
  real: TIniFile;
  sec, ent: string;
begin
  if argc < 1 then ap_raise(ap_eArgError, sToo_few_args);
  SetLength(args, argc);
  args := argv;
  real := ap_data_get_struct(This);
  sec := dl_String(args[0]);
  if argc > 1 then
  begin
    ent := dl_String(args[1]);
    result := ap_bool(real.ValueExists(sec, ent));
  end
  else
    result := ap_bool(real.SectionExists(sec));
end;

function IniFile_delete(argc: integer; argv: Pointer; This: Tvalue): Tvalue; cdecl;
var
  args: array of Tvalue;
  real: TIniFile;
  sec, ent: string;
begin
  if argc < 1 then ap_raise(ap_eArgError, sToo_few_args);
  SetLength(args, argc);
  args := argv;
  real := ap_data_get_struct(This);
  sec := dl_String(args[0]);
  if argc > 1 then
  begin
    ent := dl_String(args[1]);
    real.DeleteKey(sec, ent);
  end
  else
    real.EraseSection(sec);
  result := This;
end;

function IniFile_update(argc: integer; argv: Pointer; This: Tvalue): Tvalue; cdecl;
var
  real: TIniFile;
begin
  if argc > 0 then ap_raise(ap_eArgError, sWrong_num_of_args);
  real := ap_data_get_struct(This);
  real.UpdateFile;
  result := This;
end;

procedure Init_ini;
begin
  PhiStart;

  mIni := rb_define_module('Ini');

  cIniFile := rb_define_class_under(ap_mPhi, 'IniFile', ap_cObject);
  rb_define_singleton_method(cIniFile, 'new', @IniFile_new, 1);
  DefineMethod(cIniFile, '[]', IniFile_aref);
  DefineMethod(cIniFile, '[]=', IniFile_aset);
  DefineMethod(cIniFile, 'exist?', IniFile_exist_p);
  DefineMethod(cIniFile, 'delete', IniFile_delete);
  DefineMethod(cIniFile, 'update', IniFile_update);
  rb_define_attr(cIniFile, 'file_name', 1, 0);
end;

exports
  Init_ini;

end.
