/* -------------------------------------------------------------------------
 * Project: Mac Notifier Support
 * Name:    macnotfy.c
 * Author:  Stefan CSomor
 * Purpose: Mac Notifier main file
 * CVSID:   $Id: macnotfy.cpp 26277 2004-03-20 07:43:01Z SC $
 * -------------------------------------------------------------------------
 */

#include "wx/wx.h"

#include "wx/mac/private.h"

#include "wx/mac/macnotfy.h"

const short kMaxEvents = 1000 ;

struct wxMacNotificationEvents
{
    short top ;
    short bottom ;
    
    wxMacNotificationProcPtr proc[kMaxEvents] ;
    unsigned long events[kMaxEvents] ;
    void* data[kMaxEvents] ;
} ;

typedef struct wxMacNotificationEvents wxMacNotificationEvents ;
static wxMacNotificationEvents gMacNotificationEvents ;

static ProcessSerialNumber gAppProcess ;

void wxMacWakeUp()
{
    ProcessSerialNumber psn ;
    Boolean isSame ;
    psn.highLongOfPSN = 0 ;
    psn.lowLongOfPSN = kCurrentProcess ;
    SameProcess( &gAppProcess , &psn , &isSame ) ;
    if ( isSame )
    {
#if TARGET_CARBON
        EventRef dummyEvent ;
        OSStatus err = MacCreateEvent(nil, 'WXMC', 'WXMC', GetCurrentEventTime(),
                        kEventAttributeNone, &dummyEvent);
        if (err == noErr) 
        {
            err = PostEventToQueue(GetMainEventQueue(), dummyEvent,
                                  kEventPriorityHigh);
        } 
#else
        PostEvent( nullEvent , 0 ) ;
#endif
    }
    else
    {
        WakeUpProcess( &gAppProcess ) ;
    }
}

void wxMacCreateNotifierTable()
{
      GetCurrentProcess(&gAppProcess);
    gMacNotificationEvents.top = 0 ;
    gMacNotificationEvents.bottom = 0 ;
    for ( int i = 0 ; i < kMaxEvents ; ++i )
    {
        gMacNotificationEvents.proc[i] = NULL ;
        gMacNotificationEvents.events[i] = NULL ;
        gMacNotificationEvents.data[i] = NULL ;
    }
}

void wxMacDestroyNotifierTable() 
{
}

wxMacNotifierTableRef wxMacGetNotifierTable() 
{
    return (wxMacNotifierTableRef) &gMacNotificationEvents ;
}

void wxMacAddEvent( 
    wxMacNotifierTableRef table , 
    wxMacNotificationProcPtr handler , 
    unsigned long event , 
    void* data , 
    short wakeUp ) 
{
    wxMacNotificationEvents *e = (wxMacNotificationEvents *) table ;
    wxASSERT_MSG( handler != NULL , wxT("illegal notification proc ptr") ) ;
    /* this should be protected eventually */
    short index = e->top++ ;
    
    if ( e->top == kMaxEvents )
        e->top = 0 ;

    e->proc[index] = handler ;
    e->events[index] = event ;
    e->data[index] = data ;
    if ( wakeUp )
        wxMacWakeUp() ;
}

bool gInProcessing = false ;

void wxMacRemoveAllNotifiersForData( wxMacNotifierTableRef table , void* data ) 
{
    wxMacNotificationEvents *e = (wxMacNotificationEvents *) table ;
    /* this should be protected eventually */
    short index = e->bottom ;
    
    while ( e->top != index )
    {
        if ( e->data[index] == data )
            e->data[index] = NULL ;
        index++ ;
        if ( index == kMaxEvents )
            index = 0 ;
    }
}

void wxMacProcessNotifierEvents()
{
    //  if ( gInProcessing )
    //      return ;
    
    gInProcessing = true ;
    if ( gMacNotificationEvents.top != gMacNotificationEvents.bottom )
    {
        // we only should process the notifiers that were here when we entered it
        // otherwise we might never get out...  
        short count = gMacNotificationEvents.top - gMacNotificationEvents.bottom ;
        if ( count < 0 )
            count += kMaxEvents ;
        
        while ( count-- )
        {
            // consume event at bottom
            short index = gMacNotificationEvents.bottom++ ;
            if ( gMacNotificationEvents.bottom == kMaxEvents )
                gMacNotificationEvents.bottom = 0 ;
            void* data = gMacNotificationEvents.data[index] ;
            unsigned long event = gMacNotificationEvents.events[index] ;
            wxMacNotificationProcPtr handler =  gMacNotificationEvents.proc[index] ;
            
            gMacNotificationEvents.data[index] = NULL ;
            gMacNotificationEvents.events[index] = NULL ;
            gMacNotificationEvents.proc[index]  = NULL ;
            
            if ( handler )
                handler( event , data  ) ;
        }
    }
    gInProcessing = false ;
}

void wxMacProcessNotifierAndPendingEvents() 
{
    wxMacProcessNotifierEvents() ;
    wxTheApp->ProcessPendingEvents() ;
}
