/*
 * Copyright (c) 2012-2014, 2017-2019, 2024, 2026 LAAS/CNRS
 * All rights reserved.
 *
 * Redistribution and use  in source  and binary  forms,  with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *   1. Redistributions of  source  code must retain the  above copyright
 *      notice and this list of conditions.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice and  this list of  conditions in the  documentation and/or
 *      other materials provided with the distribution.
 *
 *                                      Anthony Mallet on Thu Mar 15 2012
 */
#ifndef H_CCLIENT_PRIVATE
#define H_CCLIENT_PRIVATE

/* Export symbols from the API - might be tweaked for different
 * targets/compilers */
#define genom_public __attribute__((visibility ("default")))

#include <pthread.h>

#include <vector>

#include "boost/shared_ptr.hpp"
#include "ros/node_handle.h"
#include "actionlib/client/action_client.h"

#include "genom3/c/client.h"

#define ROS_CLIENT_FREE		0
#define ROS_CLIENT_WAIT_ACK	1
#define ROS_CLIENT_WAIT_TERM	2
#define ROS_CLIENT_TERM		3
#define ROS_CLIENT_TIMEOUT	4

struct ros_options {
  char *instance;
  int topics_timeout;
};

/* This hackery is required to store a generic pointer on a template <class T>
 * class ClientGoalHandle and invoke cancel() on it, because the actionlib
 * client goal handle does not derive from a common base class... */
class genom_gh {
  struct iface {
    virtual void cancel() = 0;
    virtual ~iface() {}
  };

  template<class T> struct generic : iface {
    generic(const T &t) : gh(t) {}
    void cancel() { gh.cancel(); }
   private:
    T gh;
  };

  boost::shared_ptr<iface> ghp;

 public:
  genom_gh() : ghp() {}
  template<class T> genom_gh(const T &gh) : ghp(new generic<T>(gh)) {}

  void cancel() { if (ghp) ghp->cancel(); }
  void reset() { if (ghp) ghp.reset(); }
};

/* stores permanent handles to each services/actions, defined in msglib.h */
struct connections_base {
  virtual ~connections_base() {}
};

/* context data */
struct genom_context_data {
  genom_client h;
};

/* the client */
struct genom_client_s : genom_context_iface {
  genom_context_data context_data;

  char *instance;
  int topics_timeout;
  ros::NodeHandle *node;
  connections_base *connections;

  genom_event ex;
  void *exdetail;
  size_t exsize;

  struct request {
    const struct genom_service_info *info;
    genom_gh gh;
    int status, pstatus;
    genom_event error;
    void *exdetail;
    void (*exfini)(genom_event, void *);
    void *output;
    genom_request_cb sentcb, donecb;
    void *cb_data;
  };
  std::vector<request> active_rqst;
  int nextrqst;
  pthread_mutex_t activelk;

  int evpipe[2], evpending;
  genom_client next;
};

genom_client	ros_newclient(void);
void		ros_delclient(genom_client h);
genom_event	ros_init(genom_client h, int argc, char *argv[]);
void		ros_fini(void);
genom_event	ros_getopt(genom_client h, int argc, char *argv[],
                        struct ros_options *opts);

const struct genom_service_info *
		ros_service_info(genom_client h, int rqstid);
genom_event	ros_waitevent(genom_client h);
genom_event	ros_waitack(genom_client h, int rqstid);
genom_event	ros_waitterm(genom_client h, int rqstid);
int		ros_done(genom_client h, int rqstid);
genom_event	ros_abort(genom_client h, int rqstid);
genom_event	ros_clean(genom_client h, int rqstid);
genom_event	ros_doevents(genom_client h);
genom_event	ros_rqstresult(genom_client h, int rqstid, genom_event *report,
			void **output, void **exdetail);
genom_event	ros_newrqst(genom_client h, size_t outsize, int &rqstid);
void		ros_evtask_signal(void);

genom_event	ros_client_raise(genom_event ex, const void *detail,
                        size_t size, genom_context self);
const void *	ros_client_raised(genom_event *ex,
                        genom_context self);

/* compat 1.33, will be removed */
extern "C"
genom_event	ros_result(genom_client h, int rqstid, genom_event *report,
			void **output, void **exdetail)
  __attribute__((deprecated("use ros_rqstresult() instead")));

#endif /* H_CCLIENT_PRIVATE */
