
// SPDX-License-Identifier: CC-BY-NC-SA-4.0
//
// Copyright (C) 2026 Bit by Bit Signal Processing LLC (https://bxbsp.com)
//
// This work is placed under the "Creative Commons Attribution
// NonCommercial ShareAlike 4.0 International" license, known
// by the shortened acronym "CC-BY-NC-SA-4.0".
//
// This work 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.
//
// A CC-BY-NC-SA-4.0 license allows you to use this work for
// noncommercial purposes so long as attribution is made to the
// original author.  Modified versions of this work may be distributed,
// but only under the same license.  For further details, see the
// Creative Commons License "CC-BY-NC-SA-4.0".
//
// You should have received a copy of the CC-BY-NC-SA-4.0 license
// along with this work. If not, see
// <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
//


#include "send_events.hh"

struct dint
{
  int x;

  operator int() { return x; }
  dint(const int x) { this->x = x; }
  dint() { x = 0; }
};


bool receive1(class S*    sender,
	      int         event_data,
	      class R*    receiver,
	      int         receiver_data,
	      int&        event_return);

bool receive2(class S*    sender,
	      int         event_data,
	      class R*    receiver,
	      int         receiver_data,
	      int&        event_return);

bool receive3(class S*    sender,
	      dint        event_data,
	      class R*    receiver,
	      int         receiver_data,
	      int&        event_return);

//
// This shows how a single sender can send multiple event types.  Even the same types,
// if they're wrapped in a structure properly.
//
class S : public sending_base_class<int, int>, public sending_base_class<dint, int>
{
public:
  int ID;
  void send_some_events()
  {
    int   to_send[]    = { 123, 456, 1, 2 };
    int   num_to_send  = sizeof(to_send) / sizeof(to_send[0]);

    for(int i=0; i<num_to_send; i++)
      {
	int   returned = 0;
	{
	  // This shows how to explicitly choose a send_event based on argument types.
	  bool  handled = sending_base_class<int,int>::send_event(this, to_send[i], returned);
	  printf("Sent int event %d, got back event %d, handled=%d\n", to_send[i], returned, handled);
	}
	{
	  bool  handled = sending_base_class<dint,int>::send_event(this, to_send[i], returned);
	  printf("Sent int event %d, got back event %d, handled=%d\n", to_send[i], returned, handled);
	}    
      }
  }
    
  S(int ID) { this->ID = ID; }
};


class R
{
public:
  int ID;

  connection <S, int, R, int, int>  connector_1;
  connection <S, int, R, int, int>  connector_2;
  connection <S, dint, R, int, int> connector_3;

  R(int ID)
    :   connector_1(this, 1000, receive1),
	connector_2(this, 2000, receive2),
	connector_3(this, 3000, receive3)
  {
    this->ID = ID;
  }
};


int main()
{
  S sender1(100000);
  S sender2(200000);

  R receiver1(10000);
  R receiver2(20000);

  sender1.sending_base_class<int,int>::add_receiver(&receiver1.connector_1);
  sender1.sending_base_class<int,int>::add_receiver(&receiver2.connector_1);
  sender1.sending_base_class<dint,int>::add_receiver(&receiver1.connector_3);

  printf("\n"
	 "Sending events from sender1:  Set up to receive on connector_1 to function 1 from both receivers.\n"
	 "\n");

  sender1.send_some_events();
  
}


bool receive1(S*    sender,
	      int   event_data,
	      R*    receiver,
	      int   receiver_data,
	      int&  event_return)
{
  event_return = sender->ID + receiver->ID + event_data;
  bool handled = (event_data&1)==1;
  
  printf("Receive function 1 got a message:\n"
	 "  Sender:        %8d\n"
	 "  Event:         %8d\n"
	 "  Receiver:      %8d\n"
	 "  Receiver_Data: %8d\n"
	 "  Return:        %8d\n"
	 "  Handled:       %8d\n",
	 sender->ID,
	 event_data,
	 receiver->ID,
	 receiver_data,
	 event_return,
	 handled);

  return handled;
}



bool receive2(S*    sender,
	      int   event_data,
	      R*    receiver,
	      int   receiver_data,
	      int&  event_return)
{
  event_return = sender->ID + receiver->ID + event_data;
  bool handled = (event_data&1)==1;
  
  printf("Receive function 2 got a message:\n"
	 "  Sender:        %8d\n"
	 "  Event:         %8d\n"
	 "  Receiver:      %8d\n"
	 "  Receiver_Data: %8d\n"
	 "  Return:        %8d\n"
	 "  Handled:       %8d\n",
	 sender->ID,
	 event_data,
	 receiver->ID,
	 receiver_data,
	 event_return,
	 handled);

  return handled;
}


bool receive3(S*    sender,
	      dint   event_data,
	      R*    receiver,
	      int   receiver_data,
	      int&  event_return)
{
  event_return = sender->ID + receiver->ID + event_data;
  bool handled = (event_data&1)==1;
  
  printf("Receive function 3 got a message:   *****  DINT *****\n"
	 "  Sender:        %8d\n"
	 "  Event:         %8d\n"
	 "  Receiver:      %8d\n"
	 "  Receiver_Data: %8d\n"
	 "  Return:        %8d\n"
	 "  Handled:       %8d\n",
	 sender->ID,
	 (int)event_data,
	 receiver->ID,
	 receiver_data,
	 event_return,
	 handled);

  return handled;
}


//
// Sending class:
//
//     class S : public sending_class { ... };
//
// Receiving function:
//
//     bool receive_function ( S*  sender,
//     			       E   event_data,
//    			       R*  receiver_class,
//    			       D   receiver_data,
//                             ER& event_return);
//
//     The return value is true if the event was handled and should be
//     sent to no further listeners.
//
// Typically members of class R:
//
//     D receiver_data;
//
//     connection<S, E, R, D, ER>* connector;
//
// Initialization of connector:
//
//     R* receive_class = new R(...);
//
//     connector = new connection<S, E, R, D, ER> ( receive_class, receiver_data, receive_function );
//
//     S sender;
//
//     sender.add_receiver(connector);
//
//          ...
//
//     sender.release_receiver(connector);
//
// For sender to send an event from a member function, using the function send_event*(
// inherited from sending_class:
//
//     E  event_data;
//     ER event_return;
//
//     bool handled = send_event(this, event_data, event_return);
