unit uClientDataSet;

interface

uses Rubies, DBClient;

var
  cClientDataSet: Tvalue;

function ap_cClientDataSet: Tvalue;
procedure Init_ClientDataSet;

implementation

uses
  SysUtils, Classes,
  DB,
  uDefUtils, Pythia,
  RDBHandle, uRDB, uDataSet, uIndexDef;

function ap_cClientDataSet: Tvalue;
begin
  result := cClientDataSet;
end;

procedure ClientDataSet_free(real: TClientDataSet); cdecl;
begin
//rb_p(ap_String('ClientDataSet_free1:'+real.ClassName));
  real.SetProvider(nil);
  if real.Active then real.Close;
  CompoFree(real);
//rb_p(ap_String('ClientDataSet_free2'));
end;

// CompoAlloc modified
function ClientDataSet_alloc1(This: Tvalue; real: TClientDataSet): Tvalue;
begin
  if real = nil then begin result := Qnil; exit; end;
  PhiObjectList.Add(real);
  result := rb_data_object_alloc(This, real, nil, @ClientDataSet_free);
  rb_iv_set(result, '@events', rb_hash_new);
  real.tag := result;
end;

procedure ClientDataSet_setup(obj: Tvalue; real: TClientDataSet);
begin
  DataSet_setup(obj, real);
  rb_iv_set(obj, '@index_defs', ap_iIndexDefs(real.IndexDefs, obj));
end;

function ClientDataSet_allocate(This: Tvalue): Tvalue; cdecl;
var
  real: TClientDataSet;
begin
  real := TClientDataSet.Create(nil);
  result := ClientDataSet_alloc1(This, real);
  ClientDataSet_setup(result, real);
end;

function ClientDataSet_get_change_count(This: Tvalue): Tvalue; cdecl;
var
  real: TClientDataSet;
begin
  real := ap_data_get_struct(This);
  result := ap_Integer(real.ChangeCount);
end;

function ClientDataSet_save(This, file_name, data_packet_format: Tvalue): Tvalue; cdecl;
var
  real: TClientDataSet;
  n: Integer;
  Format: TDataPacketFormat;
begin
  real := ap_data_get_struct(This);
  n := dl_Integer(data_packet_format);
  if (n < Ord(Low(TDataPacketFormat))) or (Ord(High(TDataPacketFormat)) < n) then
    ap_raise(ap_eIndexError, sOut_of_range);
  Format := TDataPacketFormat(n);
  real.SaveToFile(dl_String(file_name), Format);
  result := This;
end;

function ClientDataSet_load(This, file_name: Tvalue): Tvalue; cdecl;
var
  real: TClientDataSet;
begin
  real := ap_data_get_struct(This);
  real.LoadFromFile(dl_String(file_name));
  result := This;
end;

function ClientDataSet_find(This, v: Tvalue; nearest: Boolean): Tvalue;
var
  real: TClientDataSet;
  len: Integer;
  ptr: Pvalue;
  i: Integer;
  TmpValues: array of Variant;
  KeyValues: array of TVarRec;

  procedure set_len(_len: Integer);
  begin
    len := _len;
    SetLength(KeyValues, len);
    SetLength(TmpValues, len);
  end;

  procedure set_val(v: Tvalue; i: Integer);
  begin
    TmpValues[i] := dl_Variant(v);
    KeyValues[i].VType := vtVariant;
    KeyValues[i].VVariant := @TmpValues[i];
  end;

begin
  result := Qnil;
  try
    case RTYPE(v) of
    T_ARRAY:
      begin
        set_len(ap_ary_len(v));
        ptr := ap_ary_ptr(v);
        for i := 0 to len-1 do
        begin
          set_val(ptr^, i);
          Inc(ptr);
        end;
      end;
    else
      set_len(1);
      set_val(v, 0);
    end;
    real := ap_data_get_struct(This);
    if nearest then
    begin
      real.FindNearest(KeyValues);
      result := This;
    end else
      result := ap_bool(real.FindKey(KeyValues));
  except
    on E: Exception do
      ap_raise(ap_eDatabaseError, E.message);
  end;
end;

function ClientDataSet_find_nearest(This, v: Tvalue): Tvalue; cdecl;
begin
  result := ClientDataSet_find(This, v, True);
end;

function ClientDataSet_find_key(This, v: Tvalue): Tvalue; cdecl;
begin
  result := ClientDataSet_find(This, v, False);
end;

function ClientDataSet_get_index_names(This: Tvalue): Tvalue; cdecl;
var
  real: TClientDataSet;
begin
  result := ap_StringList_new;
  real := ap_data_get_struct(This);
  real.GetIndexNames(dl_Strings(result));
end;

function ClientDataSet_apply_updates(argc: integer; argv: Pointer; This: Tvalue): Tvalue; cdecl;
var
  real: TClientDataSet;
  p: Pvalue;
  max_errors:Integer;
begin
  max_errors := 0;
  real := ap_data_get_struct(This);
  if argc > 0 then
  begin
    p := argv;
    max_errors := dl_Integer(p^);
  end;
  result := ap_Integer(real.ApplyUpdates(max_errors));
end;

function ClientDataSet_cancel_updates(This: Tvalue): Tvalue; cdecl;
var
  real: TClientDataSet;
begin
  real := ap_data_get_struct(This);
  real.CancelUpdates;
  result := This;
end;

function ClientDataSet_create_data_set(This: Tvalue): Tvalue; cdecl;
var
  real: TClientDataSet;
begin
  real := ap_data_get_struct(This);
  result := This;
  real.CreateDataSet;
end;

function ClientDataSet_set_provider(This, v: Tvalue): Tvalue; cdecl;
var
  real: TClientDataSet;
  provider: TComponent;
begin
  real := ap_data_get_struct(This);
  provider := ap_data_get_struct(v);
  result := This;
  real.SetProvider( provider );
end;

function ClientDataSet_add_index(argc: integer; argv: Pointer; This: Tvalue): Tvalue; cdecl;
var
  real: TClientDataSet;
  p: Pvalue;
  Name, Fields: string;
  OptionsInt: Integer;
  Options: TIndexOptions absolute OptionsInt;
  DescFields: string;
  CaseInsFields: string;
  GroupingLevel: Integer;
begin
  DescFields := '';
  CaseInsFields := '';
  GroupingLevel := 0;
  real := ap_data_get_struct(This);
  p := argv;
  if argc < 3 then ap_raise(ap_eArgError, sToo_few_args);
  Name := dl_String(p^); inc(p);
  Fields := dl_String(p^); inc(p);
  OptionsInt := dl_Set(p^); inc(p);
  if argc > 3 then begin DescFields := dl_String(p^); inc(p) end;
  if argc > 4 then begin CaseInsFields := dl_String(p^); inc(p) end;
  if argc > 5 then begin GroupingLevel := dl_Integer(p^); inc(p) end;
  real.AddIndex(Name, Fields, Options, DescFields, CaseInsFields, GroupingLevel);
  result := this;
end;

procedure Init_ClientDataSet;
begin
  DefineConstSetType(mRDB, TypeInfo(TDataPacketFormat));
  cClientDataSet := DefinePersistentClass(mRDB, TClientDataSet, cDataSet, nil);
  rb_define_alloc_func(cClientDataSet, @ClientDataSet_allocate);
  DefineAttrGet(cClientDataSet, 'change_count',ClientDataSet_get_change_count);
  rb_define_method(cClientDataSet, 'save', @ClientDataSet_save, 2);
  rb_define_alias(cClientDataSet, 'save_to_file', 'save');
  rb_define_method(cClientDataSet, 'load', @ClientDataSet_load, 1);
  rb_define_alias(cClientDataSet, 'load_from_file', 'load');
  rb_define_method(cClientDataSet, 'find_nearest', @ClientDataSet_find_nearest, 1);
  rb_define_method(cClientDataSet, 'find_key', @ClientDataSet_find_key, 1);
  rb_define_method(cClientDataSet, 'index_names', @ClientDataSet_get_index_names, 0);
  rb_define_method(cClientDataSet, 'apply_updates', @ClientDataSet_apply_updates, -1);
  rb_define_method(cClientDataSet, 'cancel_updates', @ClientDataSet_cancel_updates, 0);
  rb_define_method(cClientDataSet, 'create_data_set', @ClientDataSet_create_data_set, 0);
  rb_define_method(cClientDataSet, 'set_provider', @ClientDataSet_set_provider, 1);
  rb_define_method(cClientDataSet, 'add_index', @ClientDataSet_add_index, -1);
  //TODO: lookup: TCustomClientDataSet.Lookup
end;

exports
  ap_cClientDataSet;

end.
