/*

File: notification.c
Author: Neil Cafferkey
Copyright (C) 2001-2002 Neil Cafferkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program 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. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.

*/


#include "handler_protos.h"



/****i* ram.handler/MatchNotifyRequests ************************************
*
*   NAME
*	MatchNotifyRequests --
*
*   SYNOPSIS
*	MatchNotifyRequests(handler)
*
*	VOID MatchNotifyRequests(struct Handler *);
*
*   FUNCTION
*
*   INPUTS
*
*   RESULT
*
*   EXAMPLE
*
*   NOTES
*
*   BUGS
*
*   SEE ALSO
*
****************************************************************************
*
*/

VOID MatchNotifyRequests(struct Handler *handler)
{
   struct Notification *notification,*tail;

   notification=(APTR)handler->notifications.mlh_Head;
   tail=(APTR)&handler->notifications.mlh_Tail;

   while(notification!=tail)
   {
      notification->object=
         GetObject(handler,NULL,notification->request->nr_FullName,NULL);
      notification=(APTR)((struct MinNode *)notification)->mln_Succ;
   }

   return;
}



/****i* ram.handler/NotifyAll **********************************************
*
*   NAME
*	NotifyAll --
*
*   SYNOPSIS
*	NotifyAll(handler,object,notify_links)
*
*	VOID NotifyAll(struct Handler *,struct Object *,BOOL);
*
*   FUNCTION
*
*   INPUTS
*
*   RESULT
*
*   EXAMPLE
*
*   NOTES
*
*   BUGS
*
*   SEE ALSO
*
****************************************************************************
*
*/

VOID NotifyAll(struct Handler *handler,struct Object *object,
   BOOL notify_links)
{
   struct Notification *notification,*tail;
   struct Object *request_object,*link;
   struct MinNode *link_tail,*link_node;
   BOOL found;

   if(notify_links)
   {
      object=GetRealObject(object);
      link_tail=object->hard_link.mln_Pred;
      if(link_tail==NULL)
         notify_links=FALSE;
   }

   notification=(APTR)handler->notifications.mlh_Head;
   tail=(APTR)&handler->notifications.mlh_Tail;

   while(notification!=tail)
   {
      request_object=notification->object;
      if(request_object!=NULL)
      {
         if(notify_links)
         {
            link_node=&object->hard_link;
            found=FALSE;

            while((link_node!=link_tail)&&!found)
            {
               link=HARDLINK(link_node);

               if((request_object==link)||(request_object==link->parent))
                  found=TRUE;

               link_node=link_node->mln_Succ;
            }
         }
         else
            found=
               (request_object==object)||(request_object==object->parent);

         if(found)
            Notify(handler,notification);
      }
      notification=(APTR)((struct MinNode *)notification)->mln_Succ;
   }

   return;
}



/****i* ram.handler/FindNotification ***************************************
*
*   NAME
*	FindNotification --
*
*   SYNOPSIS
*	notification = FindNotification(handler,
*	    request)
*
*	struct Notification *FindNotification(struct Handler *,
*	    struct NotifyRequest);
*
*   FUNCTION
*
*   INPUTS
*
*   RESULT
*
*   EXAMPLE
*
*   NOTES
*
*   BUGS
*
*   SEE ALSO
*
****************************************************************************
*
*/

struct Notification *FindNotification(struct Handler *handler,
   struct NotifyRequest *request)
{
   struct Notification *notification,*tail;
   BOOL found;

   notification=(APTR)handler->notifications.mlh_Head;
   tail=(APTR)&handler->notifications.mlh_Tail;
   found=FALSE;

   while((notification!=tail)&&!found)
   {
      if(notification->request==request)
         found=TRUE;
      else
         notification=(APTR)((struct MinNode *)notification)->mln_Succ;
   }

   if(!found)
      notification=NULL;

   return notification;
}



/****i* ram.handler/ReceiveNotifyReply *************************************
*
*   NAME
*	ReceiveNotifyReply --
*
*   SYNOPSIS
*	ReceiveNotifyReply(handler,message)
*
*	VOID ReceiveNotifyReply(struct Handler *,struct NotifyMessage *);
*
*   FUNCTION
*
*   INPUTS
*
*   RESULT
*
*   EXAMPLE
*
*   NOTES
*
*   BUGS
*
*   SEE ALSO
*
****************************************************************************
*
*/

VOID ReceiveNotifyReply(struct Handler *handler,
   struct NotifyMessage *message)
{
   struct Notification *notification;
   struct NotifyRequest *request;

   request=message->nm_NReq;
   notification=FindNotification(handler,request);
   FreeMem(message,sizeof(struct NotifyMessage));

   if(notification!=NULL)
   {
      request->nr_MsgCount--;

      if(request->nr_Flags&NRF_MAGIC)
      {
         request->nr_Flags&=~NRF_MAGIC;
         Notify(handler,notification);
      }
   }

   return;
}



/****i* ram.handler/Notify *************************************************
*
*   NAME
*	Notify --
*
*   SYNOPSIS
*	Notify(handler,notification)
*
*	VOID Notify(struct Handler *,struct Notification *);
*
*   FUNCTION
*
*   INPUTS
*
*   RESULT
*
*   EXAMPLE
*
*   NOTES
*
*   BUGS
*
*   SEE ALSO
*
****************************************************************************
*
*/

VOID Notify(struct Handler *handler,struct Notification *notification)
{
   struct NotifyMessage *message;
   struct NotifyRequest *request;
   ULONG flags;

   request=notification->request;
   flags=request->nr_Flags;
   if(flags&NRF_SEND_MESSAGE)
   {
      message=AllocMem(sizeof(struct NotifyMessage),MEMF_PUBLIC|MEMF_CLEAR);
      if(message!=NULL)
      {
         ((struct Message *)message)->mn_ReplyPort=handler->notify_port;
         ((struct Message *)message)->mn_Length=
            sizeof(struct NotifyMessage);
         message->nm_NReq=request;
         message->nm_Class=NOTIFY_CLASS;
         message->nm_Code=NOTIFY_CODE;

         if((flags&NRF_WAIT_REPLY)&&(request->nr_MsgCount!=0))
            request->nr_Flags|=NRF_MAGIC;
         else
         {
            PutMsg(request->nr_stuff.nr_Msg.nr_Port,(APTR)message);
            request->nr_MsgCount++;
         }
      }
   }
   else
   {
      Signal(request->nr_stuff.nr_Signal.nr_Task,
         1<<(request->nr_stuff.nr_Signal.nr_SignalNum));
   }

   return;
}



