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

#include <exec/types.h>

#include <clib/exec_protos.h>

#include "WheelMouse.h"

char *WindowModeNames[]={"Window under pointer",
                         "Active window",NULL };

char *ButtonModeNames[]={"Ignore",
                         "Shift",
                         "Shift + click",
                         "Wheel depth arrange",
                         "Shift + depth arrange",
                         "Cycle screens",NULL};

BOOL WheelMouse_Handle(struct WheelMouseContext *wmc,unsigned long signals);
void WheelMouse_Dispose(struct WheelMouseContext *wmc);


void WheelMouse_Dispose(struct WheelMouseContext *wmc)
{
  if(wmc)
  {
    if(wmc->ReplyPort)
      DeleteMsgPort(wmc->ReplyPort);
    if(wmc->SigBit>-1)
      FreeSignal(wmc->SigBit);
    free(wmc);
  }
}


struct WheelMouseContext *WheelMouse_Create()
{
  struct WheelMouseContext *wmc;
  if(!(wmc=malloc(sizeof(struct WheelMouseContext))))
    return(NULL);
  memset(wmc,0,sizeof(struct WheelMouseContext));

  wmc->Dispose=WheelMouse_Dispose;
  wmc->Handle=WheelMouse_Handle;

  wmc->WindowModeNames=WindowModeNames;
  wmc->MMBModeNames=ButtonModeNames;
  wmc->FourthButtonModeNames=ButtonModeNames;
  wmc->MouseSpeedX=wmc->MouseSpeedY=100;
  wmc->ClickToFront=FALSE;

  wmc->MainTask=FindTask(NULL);
  if((wmc->SigBit=AllocSignal(-1))==-1)
  {
    wmc->Dispose(wmc);
    return(NULL);
  }
  wmc->Signals=1<<wmc->SigBit;

  if(!(wmc->ReplyPort=CreateMsgPort()))
  {
    wmc->Dispose(wmc);
    return(NULL);
  }
  return(wmc);
}


void AddIntAtomic(int *a,int v)
{
  *a+=v;  /* Make sure your compiler generates a single instruction
             for this operation, i.e. add.l d0,(a0), and not
             move.l (a0),d1   add.l d0,d1   move.l d1,(a0) */
}


BOOL WheelMouse_Handle(struct WheelMouseContext *wmc,unsigned long signals)
{
  int distance;
  if(!(signals&wmc->Signals))
    return(TRUE);

  while(distance=wmc->ScrollX)
  {
    distance=DoScroll(wmc,FREEHORIZ,distance);
    AddIntAtomic(&wmc->ScrollX,-distance);
  }

  while(distance=wmc->ScrollY)
  {
    distance=DoScroll(wmc,FREEHORIZ|FREEVERT,distance);
    AddIntAtomic(&wmc->ScrollY,-distance);
  }

  return(TRUE);
}