// hover
// if enabled, poll every 10 cs to see if pointer has moved
// if static for long enough and over a pin, open our window

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

#include "kernel.h"
#include "swis.h"

#include "tboxlibs/toolbox.h"
#include "tboxlibs/window.h"
#include "tboxlibs/wimp.h"
#include "tboxlibs/wimplib.h"
#include "tboxlibs/event.h"
#include "tboxlibs/flex.h"

#include "msgtrans.h"
#include "pinboard.h"
#include "filermenu.h"
#include "hover.h"
#include "indirected.h"
#include "gadgetlist.h"


static int pointer_last_motion=0; // monotonic time for last movement
static int pointer_x,pointer_y; // last known position
static int hover_enabled=0;
static unsigned int hover_next_poll=0; // monotonic time for next callback
static int hover_current_pin=-1;

static ObjectId hover_window=0;

// how much we can move the pointer without resetting the timer
#define CREEP 4

// how long to stay still?
static int hover_time=100;

extern ObjectId fileinfo_win;

void hover_set_time(int new_time)
{
  if (new_time<=0) {
    hover_enabled=0;
  } else {
    hover_enabled=1;
    hover_time=new_time;
  }
}

static int hover_click(int event_code,WimpPollBlock *event,IdBlock *id,void *handle)
{
  _backdrop_state *state=handle;

  if (id->self_component==Hover_InfoButton) {
    fileinfo_fill_details(fileinfo_win,hover_current_pin,state);
    toolbox_show_object(Toolbox_ShowObject_AsMenu,fileinfo_win,Toolbox_ShowObject_AtPointer,NULL,0,0);
    return 1;
  }

  return 0;
}

static int hover_leave(int event_code,WimpPollBlock *event,IdBlock *id,void *handle)
{
  _backdrop_state *state=(_backdrop_state *)handle;
  hover_hide(state);

  return 1;
}

_kernel_oserror *hover_init(_backdrop_state *state)
{
  _kernel_oserror *e;

  // create our window
  e=toolbox_create_object(0,"hover",&hover_window);
  if (e) {
    wimp_report_error(e,0,msgtrans_lookup("_TaskName"),NULL,NULL,NULL);
    return e;
  }

  event_register_wimp_handler(hover_window,Wimp_EPointerLeavingWindow,hover_leave,state);
  event_register_wimp_handler(hover_window,Wimp_EMouseClick,hover_click,state);

  return NULL;
}

unsigned int hover_next_poll_time(void)
{
  if (!hover_enabled) return 0x7fffffff;

  return hover_next_poll;
}

static void hover_show(_backdrop_state *state,int x,int y)
{
  BBox extent;
  BBox box;
  char *filename;
  int text_width;
  WindowShowObjectBlock open;

  if (!hover_window) return;

  // set the content
  hover_current_pin=pin_check_click(pointer_x,pointer_y,state->iconsize);
  if (hover_current_pin==-1) return;

  if (pin_is_anyfile(&pinlist->info[hover_current_pin])) {
    filename=indirected(pinlist->info[hover_current_pin].data.filename_offset,char *);
    button_set_value(0,hover_window,Hover_Filename,filename);
    _swix(Wimp_TextOp,_INR(0,2)|_OUT(0),1,filename,0,&text_width);

    // set extent
    window_get_extent(0,hover_window,&extent);
    gadget_get_bbox(0,hover_window,Hover_Filename,&box);
    extent.xmax=box.xmin+text_width+52;
    window_set_extent(0,hover_window,&extent);

    // show it
    open.visible_area.xmin=x-32;
    open.visible_area.ymax=y+16;
    open.visible_area.xmax=open.visible_area.xmin+extent.xmax-extent.xmin+52; // 52=X offset of the display gadget
    open.visible_area.ymin=open.visible_area.ymax-(extent.ymax-extent.ymin);
    open.xscroll=0;
    open.yscroll=0;
    open.behind=-1;
    toolbox_show_object(0,hover_window,Toolbox_ShowObject_FullSpec,&open,0,0);
  } else {
    hover_current_pin=-1;
  }
}

void hover_hide(_backdrop_state *state)
{
  if (hover_window) toolbox_hide_object(0,hover_window);
  hover_current_pin=-1;
  _swix(OS_ReadMonotonicTime,_OUT(0),&pointer_last_motion);
}

void hover_poll(int now,_backdrop_state *state)
{
  WimpGetPointerInfoBlock ptrblock;
  int d;
  int wimp_win;

  // update interval
  _swix(OS_ReadMonotonicTime,_OUT(0),&hover_next_poll);
  hover_next_poll+=10;

  // see what the mouse is or is not doing
  wimp_get_pointer_info(&ptrblock);

  window_get_wimp_handle(0,state->obj,&wimp_win);
  if (wimp_win!=ptrblock.window_handle) return; // not on the pinboard

  // have we moved?
  d=ptrblock.x-pointer_x;
  if (d<-CREEP || d>CREEP) {
    pointer_last_motion=now;
  } else {
    d=ptrblock.y-pointer_y;
    if (d<-CREEP || d>CREEP) {
      pointer_last_motion=now;
    }
  }

  pointer_x=ptrblock.x;
  pointer_y=ptrblock.y;

  if (now-pointer_last_motion>hover_time) {
    hover_show(state,pointer_x,pointer_y);
  }
}
