#include <string.h>

#include "swis.h"
#include "wimp.h"
#include "wimplib.h"
#include "events.h"

#include "debug.h"
#include "pinfilter.h"
#include "pinboard.h"
#include "module.h"

_kernel_oserror *pinfilter_handler(_kernel_swi_regs *r, void *pw);
_kernel_oserror *pinfilter_ptr_handler(_kernel_swi_regs *r, void *pw);
_kernel_oserror *pinfilter_pre_handler(_kernel_swi_regs *r, void *pw);
extern void pinfilter_veneer(void);
extern void pinfilter_ptr_veneer(void);
extern void pinfilter_pre_veneer(void);

extern int sticky_furniture_count;
extern int pollword,taskhandle;
extern int sticky_title_parent;

// need to ensure we get the prefilter so that we get all enteringwindow requests

static _kernel_oserror *pinfilter_register(int swi, int taskhandle)
{
  return _swix(swi,_INR(0,4), "PinFilter", pinfilter_veneer, module_pw, taskhandle, 
                              ~((1 << Wimp_EOpenWindow) | (1 << Wimp_ECloseWindow) | (1 << Wimp_EMouseClick)));
}

static _kernel_oserror *pinfilter_ptr_register(int swi, int taskhandle)
{
  return _swix(swi,_INR(0,4), "PinPtrFltr", pinfilter_ptr_veneer, module_pw, taskhandle, 
                              ~(1 << Wimp_EPointerEnteringWindow));
}

static _kernel_oserror *pinfilter_pre_register(int swi, int taskhandle)
{
  return _swix(swi,_INR(0,3), "PinPreFltr", pinfilter_pre_veneer, module_pw, taskhandle);
}

_kernel_oserror *pinfilter_start(int taskhandle)
{
  _kernel_oserror *e;
  e=pinfilter_register(Filter_RegisterPostFilter, taskhandle);
  if (e) return e;

  e=pinfilter_ptr_register(Filter_RegisterPostFilter, 0);
  if (e) {
    pinfilter_register(Filter_DeRegisterPostFilter, taskhandle);
  } else {
    e=pinfilter_pre_register(Filter_RegisterPreFilter, 0);
    if (e) {
      pinfilter_register(Filter_DeRegisterPostFilter, taskhandle);
      pinfilter_ptr_register(Filter_DeRegisterPostFilter, 0);
    }
  }

  return e;
}

_kernel_oserror *pinfilter_stop(int taskhandle)
{
  pinfilter_ptr_register(Filter_DeRegisterPostFilter,0);
  pinfilter_register(Filter_DeRegisterPostFilter, taskhandle);
  pinfilter_pre_register(Filter_DeRegisterPreFilter, 0);
  return NULL;
}

struct pinprefilter_handler_args {
  int event_mask;
  WimpPollBlock *wpb;
  int taskhandle;
  int pollword;
};

_kernel_oserror *pinfilter_pre_handler(_kernel_swi_regs *r,void *pw)
{
  IGNORE(pw);

  struct pinprefilter_handler_args *a=(struct pinprefilter_handler_args *)r;
  a->event_mask &= ~(1 << Wimp_EPointerEnteringWindow);
  return NULL;
}

struct pinfilter_handler_args {
  int event_code;
  WimpPollBlock *wpb;
  int taskhandle;
};

_kernel_oserror *pinfilter_handler(_kernel_swi_regs *r, void *pw)
{
  IGNORE(pw);
  struct pinfilter_handler_args *a=(struct pinfilter_handler_args *)r;

  switch (a->event_code)
  {
    case Wimp_EOpenWindow:
    {
      FilterOpenEvent *foe = (FilterOpenEvent *)a->wpb;
      if (a->wpb->open_window_request.window_handle==sticky_title_parent) {
        memmove(&foe->open_window,&a->wpb->open_window_request,sizeof(WimpOpenWindowRequestEvent));
        foe->size=sizeof(FilterOpenEvent);
        foe->ref=0;
        foe->event_code=TEvent_Sticky_Open;
        foe->flags=0;
        a->event_code=0x200;
      }
      break;
    }

    case Wimp_ECloseWindow:
    {
      FilterCloseEvent *fce = (void*) a->wpb;
      fce->window_handle = a->wpb->close_window_request.window_handle;
      fce->size = sizeof(FilterCloseEvent);
      fce->ref = 0;
      fce->event_code = TEvent_Sticky_CloseClick;
      fce->flags = 0;
      a->event_code = 0x200;
      break;;
    }

    case Wimp_EMouseClick:
      if (a->wpb->mouse_click.window_handle == WimpWindow_Iconbar)
      {
        FilterEvent *fe = (void*) a->wpb;
        fe->buttons = a->wpb->mouse_click.buttons;
        fe->ref = 0;
        fe->flags = 0;
        fe->event_code = TEvent_Tinydir_FilterClick;
        fe->size = sizeof(FilterEvent);
        /* icon handle unchanged */
        a->event_code = 0x200;
        break;;
      }
      else if (a->wpb->mouse_click.buttons == Wimp_MouseButtonMenu) 
      {
        FilterMenuEvent *fe = (void*) a->wpb;
        fe->mouse_click=a->wpb->mouse_click;
        fe->ref = 0;
        fe->flags = 0;
        fe->event_code = TEvent_MenuClick;
        fe->size = sizeof(FilterMenuEvent);
        a->event_code = 0x200;
        break;;
      }
  }
  return NULL;//event_code;
}

_kernel_oserror *pinfilter_ptr_handler(_kernel_swi_regs *r, void *pw)
{
  IGNORE(pw);
  struct pinfilter_handler_args *a=(struct pinfilter_handler_args *)r;
  int win_th;

  if (sticky_furniture_count==0) return NULL; // nothing to do

  // pass this down to our task as well if it's not our window
  // get taskhandle of the window.  If it's not ours, set the pollword
  int message[4]={16,0,0,0};
  wimp_send_message(19,message,a->wpb->pointer_entering_window.window_handle,-1,&win_th);
  if (win_th!=taskhandle)  pollword|=2;

  return NULL;
}
