/*

Copyright (C) 2010-2016 Olaf Till <i7tiol@t-online.de>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

*/

// PKG_ADD: autoload ("network_get_info", "parallel_interface.oct");
// PKG_DEL: autoload ("network_get_info", "parallel_interface.oct", "remove");

#include <octave/oct.h>
#include <octave/dirfns.h>
#include <octave/oct-map.h>
#include <octave/oct-env.h>

#include "parallel-gnutls.h"

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>

DEFUN_DLD (network_get_info, args, ,
           "-*- texinfo -*-\n\
@deftypefn {Loadable Function} {} network_get_info (@var{connections})\n\
Return an informational structure-array with one entry for each machine specified by @var{connections}.\n\
\n\
This function can only be successfully called at the client\n\
machine. See @code{pconnect} for a description of the\n\
@var{connections} variable. @var{connections} can contain all\n\
connections of the network, a subset of them, or a single\n\
connection. For the local machine (client), if contained in\n\
@var{connections}, some fields of the returned structure may be\n\
empty.\n\
\n\
The fields of the returned structure are @code{local_machine}: true\n\
for the connection representing the local machine, @code{nproc}:\n\
number of usable processors of the machine, @code{nlocaljobs}:\n\
configured number of local processes on the machine, @code{peername}:\n\
name of the machine (empty for local machine), @code{open}: true if\n\
the connection is open, @code{network_id}: uuid of the network,\n\
@code{real_node_id}: internal id assigned to node, @code{0} for\n\
client, servers starting with @code{1}.\n\
\n\
@seealso{pconnect, pserver, reval, psend, precv, sclose, parallel_generate_srp_data, select_sockets}\n\
@end deftypefn")
{
  std::string fname ("network_get_info");

  if (args.length () != 1 ||
      args(0).type_id () != octave_parallel_connections::static_type_id ())
    {
      print_usage ();

      return octave_value_list ();
    }

  const octave_base_value &rep = args(0).get_rep ();
  const octave_parallel_connections &cconns =
    dynamic_cast<const octave_parallel_connections&> (rep);
  octave_parallel_connections_rep *conns = cconns.get_rep ();
  int nconns = conns->get_connections ().numel ();

  if (conns->get_whole_network ()->is_closed ())
    {
      error ("%s: network is closed", fname.c_str ());

      return octave_value_list ();
    }

  if (conns->is_server ())
    {
      error ("%s: 'network_get_info' can't be called at the server side",
             fname.c_str ());

      return octave_value_list ();
    }

  const char *fieldnames[] = {"local_machine",
                              "nproc",
                              "nlocaljobs",
                              "peername",
                              "open",
                              "network_id",
                              "real_node_id",
                              NULL};

  octave_fields fields (fieldnames);

  octave_map retval (dim_vector (nconns, 1), fields);

  octave_scalar_map node_info (fields);

  for (octave_idx_type i = 0; i < nconns; i++)
    {
      if (conns->get_connections ()(i)->is_pseudo_connection ())
        node_info.setfield ("local_machine", true);
      else
        node_info.setfield ("local_machine", false);

      node_info.setfield ("nproc", conns->get_connections ()(i)->get_nproc ());
      node_info.setfield ("nlocaljobs",
                          conns->get_connections ()(i)->get_nlocaljobs ());
      node_info.setfield ("peername",
                          conns->get_connections ()(i)->get_peer_name ());
      node_info.setfield ("open", conns->get_connections ()(i)->is_open ());
      node_info.setfield ("network_id",
                          conns->get_connections ()(i)->get_uuid ());
      node_info.setfield ("real_node_id",
                          conns->get_connections ()(i)->peer_node_n);

      retval.assign (i, node_info);
    }

  return octave_value (retval);
}

/*
;;; Local Variables: ***
;;; mode: C++ ***
;;; End: ***
*/
