#include <stdio.h>

#include <exec/types.h>

#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <graphics/clip.h>
#include <devices/inputevent.h>

#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/layers_protos.h>

#include "WheelMouse.h"

#include "Scroll.h"
#include "RawKey.h"

extern struct IntuitionBase *IntuitionBase;

struct Window *WindowUnderPointer();

void SendIDCMP(struct WheelMouseContext *wmc,int class,int code,int qualifier,struct IntuiMessage *im)
{
  struct Window *win=wmc->Window;
  struct Gadget *gg=wmc->Gadget;
  im->IDCMPWindow=win;
  im->IAddress=gg;
  im->Class=class;
  im->Code=code;
  im->Qualifier=qualifier;
  im->MouseX=win->MouseX;
  im->MouseY=win->MouseY;
  im->ExecMessage.mn_ReplyPort=wmc->ReplyPort;
  im->Seconds=IntuitionBase->Seconds; im->Micros=IntuitionBase->Micros;
  im->SpecialLink=NULL;
  PutMsg(win->UserPort,(struct Message *)im);
}


void NudgePropGadget(struct Gadget *gg,struct Window *win,int axis,int direction)
{
  struct PropInfo *pi=(struct PropInfo *)gg->SpecialInfo;

  long current,offset;

  if(axis==FREEVERT)
  {
    current=pi->VertPot;
    offset=pi->VPotRes;
    current+=(direction*offset)/4;
    if(current<0) current=0;
    if(current>0xffff) current=0xffff;
    pi->VertPot=current;
  }

  if(axis==FREEHORIZ)
  {
    current=pi->HorizPot;
    offset=pi->HPotRes;
    current+=(direction*offset)/4;
    if(current<0) current=0;
    if(current>0xffff) current=0xffff;
    pi->HorizPot=current;
  }

}


struct Gadget *FindPropGadget(struct Window *win,long type)
{
  struct Gadget *gg=win->FirstGadget,*bestgadget=NULL;
  int gx,gy,dd,distance=32767;
  while(gg)
  {
    if((gg->GadgetType&GTYP_GTYPEMASK)==GTYP_PROPGADGET)
    {
      struct PropInfo *pi=(struct PropInfo *)gg->SpecialInfo;
      if(pi)
      {
        if(pi->Flags&type)
        {
          if(type==FREEVERT)
          {
            gx=gg->LeftEdge+gg->Width;
            if(gg->Flags&GFLG_RELRIGHT)
              gx+=win->Width;
            dd=gx-win->MouseX;
            if(dd<0)
              dd=-dd+win->Width; /* bias to left of scrollbar */
            gy=(gg->TopEdge+gg->Height+32)-win->MouseY;
            if((gg->TopEdge-win->MouseY)*(gg->TopEdge-win->MouseY)<(gy*gy))
              gy=gg->TopEdge-win->MouseY;
            if(gy<0)
              gy=-gy;
            dd+=gy;
          }
          if(type==FREEHORIZ)
          {
            gx=gg->TopEdge+gg->Height;
            if(gg->Flags&GFLG_RELBOTTOM)
              gx+=win->Height;
            dd=gx-win->MouseY;
            if(dd<0)
              dd=-dd+win->Height; /* bias to top of scrollbar */
            gy=(gg->LeftEdge+gg->Width+32)-win->MouseX;
            if((gg->LeftEdge-win->MouseX)*(gg->TopEdge-win->MouseX)<(gy*gy))
              gy=gg->TopEdge-win->MouseX;
            if(gy<0)
              gy=-gy;
            dd+=gy;
          }
          if(dd<0) dd=-dd;
          if(dd<distance)
          {
            distance=dd;
            bestgadget=gg;
          }
        }
      }
    }
    gg=gg->NextGadget;
  }
  return(bestgadget);
}


int DoScroll(struct WheelMouseContext *wmc,int axis,int direction)
{
  struct Window *win;
  Forbid();
  if(wmc->WindowMode==OverWindow)
    win=wmc->Window=WindowUnderPointer();
  else
    win=wmc->Window=IntuitionBase->ActiveWindow;
  if(!(win))
    return(direction);
  wmc->Gadget=FindPropGadget(win,axis);
  if((!(wmc->Gadget))&&(wmc->WindowMode==OverWindow)&&((win->IDCMPFlags&IDCMP_RAWKEY)==0))
  {
    if(!(win=wmc->Window=IntuitionBase->ActiveWindow))
      return(direction);
    wmc->Gadget=FindPropGadget(win,axis);
  }
  if(wmc->Gadget)
  {
    NudgePropGadget(wmc->Gadget,win,axis,direction);
    SendIDCMP(wmc,IDCMP_GADGETDOWN,0,0,&wmc->Msg1.eim_IntuiMessage);
    SendIDCMP(wmc,IDCMP_GADGETUP,0,0,&wmc->Msg2.eim_IntuiMessage);
    RefreshGList(wmc->Gadget,wmc->Window,NULL,1);
    Permit();
    WaitPort(wmc->ReplyPort);
    GetMsg(wmc->ReplyPort);
    WaitPort(wmc->ReplyPort);
    GetMsg(wmc->ReplyPort);
    return(direction);
  }
  else if(win->IDCMPFlags&IDCMP_RAWKEY)
  {
    int code,c,d,q=0;
    d=direction;
    if(d>0)
      if(axis==FREEVERT)
        code=RK_Down;
      else
        code=RK_Right;
    else
    {
      if(axis==FREEVERT)
        code=RK_Up;
      else
        code=RK_Left;
      d=-d;
    }
    if(d>1)
      q=IEQUALIFIER_LSHIFT;
    SendIDCMP(wmc,IDCMP_RAWKEY,code,q,&wmc->Msg1.eim_IntuiMessage);
    SendIDCMP(wmc,IDCMP_RAWKEY,code|IECODE_UP_PREFIX,q,&wmc->Msg2.eim_IntuiMessage);
    Permit();
    WaitPort(wmc->ReplyPort);
    GetMsg(wmc->ReplyPort);
    WaitPort(wmc->ReplyPort);
    GetMsg(wmc->ReplyPort);
    return(direction);
    /*
    if(direction<0)
      return(-1);
    else
      return(1);
    */
  }
  Permit();
  return(direction);
}


struct Window *WindowUnderPointer()
{
  int x,y;
  unsigned long lock;
  struct Window *win=NULL;
  struct Screen *scr;
  struct Layer *layer;

  scr=IntuitionBase->FirstScreen;
  do
  {
    x=scr->MouseX; y=scr->MouseY;
    if((x<0) || (y<0))
      scr=scr->NextScreen;
  } while((scr!=NULL) && ((x<0)||(y<0)));

  if(!scr)
    return(NULL);

  layer=WhichLayer(&scr->LayerInfo,x,y);
  if(layer)
    win=layer->Window;
  return(win);
}

