/*
    ####             #    #     # #
    #   #            #    #       #          The FreeWare C library for 
    #   #  ##   ###  #  # #     # ###             RISC OS machines
    #   # #  # #     # #  #     # #  #   ___________________________________
    #   # ####  ###  ##   #     # #  #                                      
    #   # #        # # #  #     # #  #    Please refer to the accompanying
    ####   ### ####  #  # ##### # ###    documentation for conditions of use
    ________________________________________________________________________

    File:    Event.MClaimInit.c
    Author:  Copyright  1992, 1993, 1994 Jason Williams, Julian Smith.
    Version: 
    Purpose: Extension to Event.c to allow routing of specific message types
             to different windows' message handlers.
    History: 1.04 (22 Oct 1994) JW
             1.05 (14 Nov 1995) JS Made SDLS compatible.
*/


#include "EMsgDefs.h"

#define ERRBASE 1
#define ERR1 ERRBASE+0
#define ERRMESS1 "Unable to allocate memory for eventmsg claim"

Desk_linklist_header Desk_eventmsg__claimanchor = {NULL, NULL};


Desk_SDLS_PtrFn(
	static,
	Desk_bool,
	Desk_EventMsg_DispatchMessage(Desk_event_pollblock *event, void *reference)
	)
/*static Desk_bool Desk_EventMsg_DispatchMessage(Desk_event_pollblock *event, void *reference)*/
{
  Desk_message_action action;
  Desk_window_handle  window;
  Desk_eventmsg_claimrecord *ptr, *nextptr;
  Desk_eventmsg_windowrecord *wptr, *nextwptr;

  Desk_UNUSED( reference);
  
  action = event->data.message.header.action;
  switch(action)
  {
    case Desk_message_DATASAVE:
    case Desk_message_DATASAVEACK:
    case Desk_message_DATALOAD:
      window = event->data.message.data.words[0];
      break;

    case Desk_message_HELPREQUEST:
      window = event->data.message.data.helprequest.where.window;
      break;

    default:
      window = Desk_event_ANY;
      break;
  }

  ptr = (Desk_eventmsg_claimrecord *) Desk_eventmsg__claimanchor.next;
  while (ptr != NULL)
  {
    nextptr = (Desk_eventmsg_claimrecord *) ptr->header.next;

    if (ptr->messagetype == Desk_event_ANY || ptr->messagetype == action)
    {
      wptr = (Desk_eventmsg_windowrecord *) ptr->windowlist.next;
      while (wptr != NULL)
      {
        nextwptr = (Desk_eventmsg_windowrecord *) wptr->header.next;

        if (window == Desk_event_ANY || wptr->window == Desk_event_ANY ||
            wptr->window == window)
          if (wptr->handler(event, wptr->reference) == Desk_bool_TRUE)
            return(Desk_bool_TRUE);

        wptr = nextwptr;
      }
    }
    ptr = nextptr;
  }
  return(Desk_bool_FALSE);
}



extern Desk_bool Desk_EventMsg_Claim(Desk_message_action messagetype, Desk_window_handle window,
                           Desk_event_handler handler, void *reference)
{
  Desk_eventmsg_claimrecord *ptr;
  Desk_eventmsg_windowrecord *wrecord;

  ptr = (Desk_eventmsg_claimrecord *) Desk_eventmsg__claimanchor.next;
  while (ptr != NULL)            /* Find claims for this message action type */
  {
    if (ptr->messagetype == messagetype)
      break;

    ptr = (Desk_eventmsg_claimrecord *) ptr->header.next;
  }

  if (ptr == NULL)                /* No current claims, so add new claimlist */
  {
    ptr = (Desk_eventmsg_claimrecord *) Desk_DeskMem_XMalloc(sizeof(Desk_eventmsg_claimrecord));
    if (ptr == NULL)
    {
      Desk_Error_ReportInternal(ERR1, ERRMESS1);
      return(Desk_bool_FALSE);
    }

    Desk_LinkList_Init(&(ptr->header));
    ptr->messagetype = messagetype;
    Desk_LinkList_Init(&(ptr->windowlist));
    Desk_LinkList_AddToHead(&Desk_eventmsg__claimanchor, &(ptr->header));
                                          /* Insert new Desk_message_handler list */
  }

  wrecord = (Desk_eventmsg_windowrecord *) Desk_DeskMem_XMalloc(sizeof(Desk_eventmsg_windowrecord));
  if (wrecord == NULL)
  {
    Desk_Error_ReportInternal(ERR1, ERRMESS1);
    return(Desk_bool_FALSE);
  }

  Desk_LinkList_Init(&(wrecord)->header);
  wrecord->window    = window;
  wrecord->handler   = handler;
  wrecord->reference = reference;

 /* Insert new window's handler into the window list for this message action.
  * Specific-window handlers are placed on the front of the list, and non-
  * specific handlers are placed on the end, to give priority to the most
  * specific claim on any message.
  */
  if (window == Desk_event_ANY)            /* insert new window's handler in list */
    Desk_LinkList_AddToTail(&(ptr->windowlist), &(wrecord->header));
  else
    Desk_LinkList_AddToHead(&(ptr->windowlist), &(wrecord->header));

  return(Desk_bool_TRUE);
}



extern void Desk_EventMsg_Initialise(void)
{
  Desk_Event_Claim(Desk_event_USERMESSAGE, Desk_event_ANY, Desk_event_ANY,
              Desk_SDLS_dllEntry( Desk_EventMsg_DispatchMessage), NULL);
  Desk_Event_Claim(Desk_event_USERMESSAGERECORDED, Desk_event_ANY, Desk_event_ANY,
              Desk_SDLS_dllEntry( Desk_EventMsg_DispatchMessage), NULL);
}
