// union_clean.c - example for a clean use of unions

#include <stdio.h>
#include <stdlib.h>

//************************************************************
// IMPORTANT! Please note that access functions and 
// NULL-queries are missing throughout the program, because
// it's just for demo purposes. In a real-world program we
// would define access functions for every allowed access to
// members of the structs and of the union! We would also make
// all functions robust by adding the appropriate queries!
//************************************************************

//------------------------------------------------------------
typedef struct _KeyboardEvent_ KeyboardEvent;
typedef struct _MouseEvent_    MouseEvent;

typedef union _Event_   Event;

//------------------------------------------------------------
#define KBD_EVENT       1
#define MOUSE_EVENT     2

//------------------------------------------------------------
struct _KeyboardEvent_
{
  int type;
  unsigned char key;
};

//------------------------------------------------------------
struct _MouseEvent_
{
  int type;
  int x;
  int y;
  int num_clicks;
};

//------------------------------------------------------------
union _Event_
{
  int type;                      // must be the first element
  KeyboardEvent keyboard_event;
  MouseEvent    mouse_event;
};

//------------------------------------------------------------
void handleEvent(Event *event)
{
  switch(event->type)
  {
  case KBD_EVENT:
    printf("got keyboard event\n");
    printf("key is: %c\n",event->keyboard_event.key);
        // the following works too!!!!
    printf("key is (other way): %c\n\n",
           ((KeyboardEvent*)event)->key);
    break;
  case MOUSE_EVENT:
    printf("got mouse event\n");
    printf("coordinates are: %d, %d\n",
           event->mouse_event.x,
           event->mouse_event.y);
        // the following works too!!!!
    printf("coordinates are (other way): %d, %d\n\n",
           ((MouseEvent*)event)->x,
           ((MouseEvent*)event)->y);
    break;
  default:
    printf("got unknown event with type %d",
           event->type);
  }
}

//------------------------------------------------------------
int main(int argc,char *argv[])
{
  Event *event = malloc(sizeof(Event));

  event->type = KBD_EVENT;
  event->keyboard_event.key = 'x';
  handleEvent(event);

  event->type = MOUSE_EVENT;
  event->mouse_event.x = 100;
  event->mouse_event.y = 100;
  handleEvent(event);

      // other method with type-casting works too!
  {
    KeyboardEvent *kbd_event = (KeyboardEvent*)event;
    kbd_event->type = KBD_EVENT;
    kbd_event->key = 'y';
    handleEvent((Event*)kbd_event);
  }
  return(0);
}


