#ifndef FREEHDL_KERNEL_FHDL_STREAM_HH
#define FREEHDL_KERNEL_FHDL_STREAM_HH

#ifdef HAVE_SOCKET
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#endif
#include <string>
#include <iostream>

using std::istream;
using std::ostream;
using std::string;

struct fhdl_ostream_t {
  union {
    ostream *str;
    int fd;
  };
  bool active;
  bool socket_connection;

  fhdl_ostream_t();

  void bind_to_stream(ostream &os);
  void bind_to_socket(int s);

  void flush() {
    if (!socket_connection)
      str->flush();
  }

  fhdl_ostream_t &operator<<(const char *p);
  fhdl_ostream_t &operator<<(const string &a);
  fhdl_ostream_t &operator<<(const int i);
  fhdl_ostream_t &operator<<(const unsigned int i);
  fhdl_ostream_t &operator<<(const long long int i);
};


struct fhdl_istream_t {
  union {
    istream *str;
    int fd;
  };
  bool active;
  bool socket_connection;

  fhdl_istream_t();

  void bind_to_stream(istream &is);
  void bind_to_socket(int s);
  
  bool eof() { return socket_connection? false : str->eof(); }

  fhdl_istream_t &operator>>(string &a);
  fhdl_istream_t &operator>>(int &i);
  fhdl_istream_t &operator>>(unsigned int &i);
  fhdl_istream_t &operator>>(long long int &i);

  void get(char *buf, const int size, const char sep);
};


// Error stream to output error messages generated by the kernel,
// e.g. to print error messages due to invalid simulator commands
// typed in by the user
extern fhdl_ostream_t kernel_error_stream;
// Normal output messages generated by the kernel code (e.g., to print
// signal values)
extern fhdl_ostream_t kernel_output_stream;
// Errors/notes printed by the model code (e.g., assert messages)
extern fhdl_ostream_t model_output_stream;
// Input stream 
extern fhdl_istream_t input_stream;

#ifdef HAVE_SOCKET
// Sockets addresses for socket based communication
extern struct sockaddr_un      serv_addr_kernel_error;
extern struct sockaddr_un      serv_addr_kernel_output;
extern struct sockaddr_un      serv_addr_model_output;
extern struct sockaddr_un      serv_addr_input;
#endif

#endif
