library internet;

uses
  SysUtils, Classes, Controls, Rubies, uDefUtils, Pythia,
  ScktComp, InternetHandle;

{$E so}

function ap_cCustomWinSocket: Tvalue;
begin
  result := cCustomWinSocket;
end;

function CustomWinSocket_alloc(This: Tvalue; real: TCustomWinSocket): Tvalue;
begin
  result := TmpAlloc(This, real);
end;

function CustomWinSocket_get_remote_host(This: Tvalue): Tvalue; cdecl;
var
  real: TCustomWinSocket;
begin
  real := ap_data_get_struct(This);
  result := rb_str_new2(PChar(real.RemoteHost));
end;

function CustomWinSocket_get_remote_addr(This: Tvalue): Tvalue; cdecl;
var
  real: TCustomWinSocket;
begin
  real := ap_data_get_struct(This);
  result := rb_str_new2(PChar(real.RemoteAddress));
end;

function CustomWinSocket_send(This, v: Tvalue): Tvalue; cdecl;
var
  real: TCustomWinSocket;
begin
  Check_Type(v, T_STRING);
  real := ap_data_get_struct(This);
  real.SendBuf(ap_str_ptr(v)^, ap_str_len(v));
  result := This;
end;

function CustomWinSocket_recv(This, buf_len: Tvalue): Tvalue; cdecl;
var
  real: TCustomWinSocket;
  str: Tvalue;
  len: Integer;
begin
  real := ap_data_get_struct(This);
  str := rb_str_new(nil, FIX2INT(buf_len));
  len := real.ReceiveBuf(ap_str_ptr(str)^, ap_str_len(str));
  rb_str_resize(str, len);
  result := str;
end;

function ap_cServerWinSocket: Tvalue;
begin
  result := cServerWinSocket;
end;

function ServerWinSocket_alloc(This: Tvalue; real: TServerWinSocket): Tvalue;
begin
  result := TmpAlloc(This, real);
end;

function ServerWinSocket_get_connections(This: Tvalue): Tvalue; cdecl;
var
  real: TServerWinSocket;
  i: Integer;
  obj: Tvalue;
begin
  real := ap_data_get_struct(This);
  result := rb_ary_new;
  for i := 0 to real.ActiveConnections-1 do
  begin
    obj := CustomWinSocket_alloc(cCustomWinSocket, real.Connections[i]);
    if obj = 0 then Continue;
    rb_ary_push(result, obj);
  end;
end;

function ap_cClientWinSocket: Tvalue;
begin
  result := cClientWinSocket;
end;

function ClientWinSocket_alloc(This: Tvalue; real: TClientWinSocket): Tvalue;
begin
  result := TmpAlloc(This, real);
end;

function ap_cServerSocket: Tvalue;
begin
  result := cServerSocket;
end;

function ServerSocket_new(This: Tvalue): Tvalue; cdecl;
var
  real: TServerSocket;
begin
  real := TServerSocket.Create(nil);
  result := CompoAlloc(This, real);
  if @real.OnClientConnect = nil then real.OnClientConnect := Handle.doClientConnect;
  if @real.OnClientDisconnect = nil then real.OnClientDisconnect := Handle.doClientDisconnect;
  if @real.OnClientRead = nil then real.OnClientRead := Handle.doClientRead;
  if @real.OnClientWrite = nil then real.OnClientWrite := Handle.doClientWrite;
  if @real.OnClientError = nil then real.OnClientError := Handle.doClientError;
  ap_obj_call_init(result, 0, nil);
end;

function ServerSocket_get_socket(This: Tvalue): Tvalue; cdecl;
var
  real: TServerSocket;
begin
  real := ap_data_get_struct(This);
  result := ServerWinSocket_alloc(cServerWinSocket, real.Socket);
end;

function ap_cClientSocket: Tvalue;
begin
  result := cClientSocket;
end;

function ClientSocket_new(This: Tvalue): Tvalue; cdecl;
var
  real: TClientSocket;
begin
  real := TClientSocket.Create(nil);
  result := CompoAlloc(This, real);
  if @real.OnConnect = nil then real.OnConnect := Handle.doConnect;
  if @real.OnConnecting = nil then real.OnConnecting := Handle.doConnecting;
  if @real.OnDisconnect = nil then real.OnDisconnect := Handle.doDisconnect;
  if @real.OnRead = nil then real.OnRead := Handle.doRead;
  if @real.OnWrite = nil then real.OnWrite := Handle.doWrite;
  if @real.OnError = nil then real.OnError := Handle.doError;
  ap_obj_call_init(result, 0, nil);
end;

function ClientSocket_get_socket(This: Tvalue): Tvalue; cdecl;
var
  real: TClientSocket;
begin
  real := ap_data_get_struct(This);
  result := ClientWinSocket_alloc(cClientWinSocket, real.Socket);
end;

procedure Init_internet; cdecl;
begin
  PhiStart;

  cCustomWinSocket := rb_define_class_under(ap_mPhi, 'CustomWinSocket', ap_cObject);
//  DefineProp(cCustomWinSocket, TCustomWinSocket);
  DefineAttrGet(cCustomWinSocket, 'remote_host', CustomWinSocket_get_remote_host);
  DefineAttrGet(cCustomWinSocket, 'remote_addr', CustomWinSocket_get_remote_addr);
  rb_define_method(cCustomWinSocket, 'send', @CustomWinSocket_send, 1);
  rb_define_method(cCustomWinSocket, 'recv', @CustomWinSocket_recv, 1);

  cServerWinSocket := rb_define_class_under(ap_mPhi, 'ServerWinSocket', cCustomWinSocket);
  DefineAttrGet(cServerWinSocket, 'connections', ServerWinSocket_get_connections);

  cClientWinSocket := rb_define_class_under(ap_mPhi, 'ClientWinSocket', cCustomWinSocket);

  cServerSocket := DefinePersistentClass(ap_mPhi, TServerSocket, ap_cPersistent, nil);
  rb_define_singleton_method(cServerSocket, 'new', @ServerSocket_new, 0);
  DefineAttrGet(cServerSocket, 'socket', ServerSocket_get_socket);

  rb_iv_set(cServerSocket, '@events', rb_hash_new);
  DefineModuleAttrMethod(cServerSocket, 'on_client_connect');
  DefineModuleAttrMethod(cServerSocket, 'on_client_disconnect');
  DefineModuleAttrMethod(cServerSocket, 'on_client_read');
  DefineModuleAttrMethod(cServerSocket, 'on_client_write');

  cClientSocket := DefinePersistentClass(ap_mPhi, TClientSocket, ap_cPersistent, nil);
  rb_define_singleton_method(cClientSocket, 'new', @ClientSocket_new, 0);
  DefineAttrGet(cClientSocket, 'socket', ClientSocket_get_socket);

  DefineConstSetType(ap_mPhi, TypeInfo(TErrorEvent));

end;

exports
  ap_cCustomWinSocket,
  Init_internet;

end.
