# Copyright (c) 2023 Yuki Kimoto
# MIT License

class Sys::Socket {
  version_from Sys;
  allow Sys::Socket::Errno;
  
  use Fn;
  use Sys;
  use Sys::IO;
  use Sys::Socket::Constant as SOCKET;
  use Sys::Socket::Addrinfo;
  use Sys::Socket::AddrinfoLinkedList;
  use Sys::Socket::Sockaddr;
  use Sys::Socket::Sockaddr::In;
  use Sys::Socket::Sockaddr::In6;
  use Sys::Socket::Sockaddr::Un;
  use Sys::Socket::In_addr;
  use Sys::Socket::In6_addr;
  use Sys::Socket::Errno;
  
  use Sys::Socket::Error::InetInvalidNetworkAddress;
  
  native static method htonl : int ($hostlong : int);
  
  native static method htons : short ($hostshort : short);
  
  native static method ntohl : int ($netlong : int);
  
  native static method ntohs : short ($netshort : short);
  
  native static method inet_aton : int ($cp : string, $inp : Sys::Socket::In_addr);
  
  native static method inet_ntoa : string ($in : Sys::Socket::In_addr);
  
  native static method inet_pton : int ($af : int, $src : string, $dst : Sys::Socket::In_addr_base);
  
  native static method inet_ntop : mutable string ($af : int, $src : Sys::Socket::In_addr_base, $dst : mutable string, $size : int);
  
  native static method socket : int ($domain : int, $type : int, $protocol : int);
  
  native static method connect : int ($sockfd : int, $addr : Sys::Socket::Sockaddr, $addrlen : int);
  
  native static method bind : int ($sockfd : int, $addr : Sys::Socket::Sockaddr, $addrlen : int);
  
  native static method accept : int ($sockfd : int, $addr : Sys::Socket::Sockaddr, $addrlen_ref : int*);
  
  native static method listen : int ($sockfd : int, $backlog : int);
  
  native static method shutdown : int ($sockfd : int, $how : int);
  
  native static method closesocket : int ($fd : int);
  
  static method close : int ($fd : int) {
    if (Sys::OS->is_windows) {
      return Sys::Socket->closesocket($fd);
    }
    else {
      return Sys::IO->close($fd);
    }
  }
  
  native static method recv : int ($sockfd : int, $buf : mutable string, $len : int, $flags : int, $buf_offset : int = 0);
  
  native static method recvfrom : int ($sockfd : int, $buf : mutable string, $len : int, $flags : int, $src_addr : Sys::Socket::Sockaddr, $addrlen_ref : int*, $buf_offset : int = 0);
  
  native static method send : int ($sockfd : int, $buf : string, $len : int, $flags : int, $buf_offset : int = 0);
  
  native static method sendto : int ($sockfd : int, $buf : string, $len : int, $flags : int, $addr : Sys::Socket::Sockaddr, $addrlen : int, $buf_offset : int = 0);
  
  native static method getpeername : int ($sockfd : int, $addr : Sys::Socket::Sockaddr, $addrlen_ref : int*);
  
  native static method getsockname : int ($sockfd : int, $addr : Sys::Socket::Sockaddr, $addrlen_ref : int*);
  
  native static method socketpair : int ($domain : int, $type : int, $protocol : int, $pair : int[]);
  
  native static method getsockopt : int ($sockfd : int, $level : int, $optname : int, $optval : mutable string, $optlen_ref : int*);
  
  native static method setsockopt : int ($sockfd : int, $level : int, $optname : int, $optval : string, $optlen : int);
  
  native static method getaddrinfo : int ($node : string, $service : string, $hints : Sys::Socket::Addrinfo, $res_ref : Sys::Socket::AddrinfoLinkedList[]);
  
  native static method getnameinfo : int ($sa : Sys::Socket::Sockaddr, $salen : int, $host : mutable string, $hostlen : int, $serv : mutable string, $servlen : int, $flags : int);
  
  native static method gai_strerror : string ($errcode : int);
  
  native static method sockatmark : int ($sockfd : int);
  
  native static method win_set_tcp_keepalive : int ($sockfd : int, $onoff : int, $keepalivetime_ms : int, $keepaliveinterval_ms : int);
  
}