/*

Copyright (C) 2015-2018 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 3 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/>.

*/

#include <octave/oct.h>
#include <octave/Array.cc>

#include "parallel-gnutls.h"

NO_INSTANTIATE_ARRAY_SORT (octave_parallel_connection *);

INSTANTIATE_ARRAY (octave_parallel_connection *, OCTAVE_API);

// at 'p' 37 bytes must be available
int oct_parallel_store_unique_identifier (char *p)
{
  std::ifstream ifs ("/proc/sys/kernel/random/uuid");

  p[0] = '\0';

  ifs.getline (p, 37);

  ifs.close ();

  if (ifs.bad () || strlen (p) != 36)
    {
      error ("could not read uuid");

      return -1;
    }
  else
    return 0;
}

int octave_parallel_connection::wait_for_errors_or_data (void)
{
  if (! cmd_stream)
    {
      _p_error ("can't poll since no command stream present");

      return -1;
    }

  if (! data_stream)
    {
      _p_error ("can't poll since no data stream present");

      return -1;
    }

  if (! cmd_stream->get_strbuf ()->good ())
    {
      _p_error ("can't poll since command stream not good");

      return -1;
    }

  if (! data_stream->get_strbuf ()->good ())
    {
      _p_error ("can't poll since data stream not good");

      return -1;
    }

  int ret = 0;

  // block until something is readable
  int rev1 = 0, rev2 = 0;
  if (gnulib_pollin_2_block (cmd_stream->get_strbuf ()->get_fid (),
                             data_stream->get_strbuf ()->get_fid (),
                             &rev1, &rev2)
      == -1)
    {
      _p_error ("error in poll()");

      return (-1);
    }

  if (rev1)
    ret = poll_for_errors ();

  return ret;
}

DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_parallel_connections,
                                     "parallel cluster connections",
                                     "pconnections")

octave_value octave_parallel_connections::do_index_op
(const octave_value_list& idx, bool resize_ok)
{
  octave_value err_retval;

  octave_idx_type n_idx = idx.length ();

  switch (n_idx)
    {
    case 0: // but actually this seems to be handled before, directly, by Octave
      return octave_value (this, true);
    case 2:
      {
        idx_vector i;
        bool err;
        SET_ERR (i = idx(1).index_vector (), err);
        if (err || ! i.is_colon ())
          {
            error ("only colon allowed as second index");
            return err_retval;
          }
      }
    case 1:
      {
        idx_vector i;
        CHECK_ERROR (i = idx(0).index_vector (), err_retval,
                     "invalid index");
        if (i.is_colon ())
          return octave_value (this, true);
        if (! i.length ())
          return octave_value (new octave_parallel_connections ());
        octave_idx_type n = rep->subnet.numel ();
        if (i.extent (n) != n)
          {
            error ("index out of range");
            return err_retval;
          }
        octave_idx_type len = i.length ();
        if (i.IDXVECTOR_ISVECTOR ())
          {
            if (i.sorted (true).length () < len)
              {
                error ("index not unique");
                return err_retval;
              }
          }
        octave_parallel_network::connarray nsubnet (dim_vector (len, 1));
        i.index (rep->subnet.data (), n, nsubnet.fortran_vec ());
        return octave_value (new octave_parallel_connections
                             (rep->network, rep->uuid.c_str (),
                              rep->server, nsubnet));
      }
    default:
      error ("no more than 2 indices possible for this type");
      return err_retval;
    }        
}
