#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "kernel.h"
// oslib
#include "oslib/os.h"
#include "oslib/osword.h"
#include "mcode.h"

#include "server.h"



#ifndef BUILD_MODULE
// build application (run it in a task window)

int main(int argc, char **argv) {
  int nRet = server_start(5902, "henrik");
  if (nRet)    // port and password
  {
    printf ("Returned %d\n", nRet);
    exit(0);
  }
  server_set_flag(SERVER_FLAG_SUPPORT_MOUSE,    SERVER_FLAG_SET);
  server_set_flag(SERVER_FLAG_SUPPORT_KBD,      SERVER_FLAG_SET);
  server_set_flag(SERVER_FLAG_SWAP_MENU_ADJUST, SERVER_FLAG_SET);
  atexit(server_stop);
  while (1)
    server_poll();
}



#else
// build module

static char password[9]      = "";
static int port               = 5901;
static int timer_waiting      = 0;
static int callback_waiting   = 0;
static int nudge_delay        = 25; // centiseconds without callbacks before nudging mouse
static int last_callback_time = 0;  // time of last callback

static int frontend_start(void *pw);
static int frontend_stop(void *pw);

// veneers
int timer(_kernel_swi_regs *r, void *pw);
int callback(_kernel_swi_regs *r, void *pw);


_kernel_oserror err_bad_arguments_0 = { 1, "Syntax: *vncserv_start <port> <password>" };


// ---------------------------------------------------------------------
// module api


_kernel_oserror *module_init(char *tail, int base, void *pw) {
  return NULL;
}



_kernel_oserror *module_finalise(int fatal, int base, void *pw) {
  frontend_stop(pw);
  return NULL;
}


_kernel_oserror *command_handler(char *args, int argc, int cmdno, void *pw) {

  switch (cmdno) {
  case 0:           // *vncserv_start <port> <password>
    {
      int prt;
      char pwd[256];
      if (sscanf(args, "%d %s", &prt, pwd) == 2) {
        port = prt;
        strncpy(password, pwd, 8);
        password[8] = '\0';
        frontend_start(pw);
        return NULL;
      } else
        return &err_bad_arguments_0;
    }
    break;

  case 1:           // *vncserv_stop
    frontend_stop(pw);
    break;

  case 2:           // *vncserv_mouse_kbd
    server_set_flag(SERVER_FLAG_SUPPORT_MOUSE, SERVER_FLAG_SET);
    server_set_flag(SERVER_FLAG_SUPPORT_KBD, SERVER_FLAG_SET);
    break;

  case 3:           // *vncserv_swap_adjust_menu 0 | 1
    if (atoi(args))
      server_set_flag(SERVER_FLAG_SWAP_MENU_ADJUST, SERVER_FLAG_SET);
    else
      server_set_flag(SERVER_FLAG_SWAP_MENU_ADJUST, SERVER_FLAG_CLEAR);
    break;

  case 4:           // *vncserv_dont_nudge_mouse [<centiseconds>]
    nudge_delay = 0x40000000;
    break;
  }
  return NULL;      // or pointer to error-block
}


// ---------------------------------------------------------------------
// handlers and stuff

int timer_handler(_kernel_swi_regs *r, void *pw) {
  if (clock() > last_callback_time + nudge_delay) {
    oswordpointer_position_block pos;
    // release mouse keys
    server_release_key(0x70);
    server_release_key(0x71);
    server_release_key(0x72);

    pos.op = oswordpointer_OP_SET_POSITION;
    pos.x = 2*mouse_x;
    pos.y = 2*(screensize_y - mouse_y + 1);
    xoswordpointer_set_position(&pos);
    pos.op = oswordpointer_OP_SET_POSITION;
    pos.x = 2*mouse_x;
    pos.y = 2*(screensize_y - mouse_y);
    xoswordpointer_set_position(&pos);
    last_callback_time = clock();
  }
  if (callback_waiting)  return 1;
  xos_add_call_back((void *)callback, pw);
  callback_waiting = 1;
  return 1;
}


int callback_handler(_kernel_swi_regs *r, void *pw) {
  last_callback_time = clock();
  server_poll();
  callback_waiting = 0;
  return 1;                   // always return a value != 0 !!!!!
}

// ---------------------------------------------------------------------
// frontend

int frontend_start(void *pw) {
  server_start(port, password);
  xos_call_every(1, (void *)timer, pw);
  timer_waiting = 1;
  last_callback_time = clock();
  return 0;
}


int frontend_stop(void *pw) {
  if (timer_waiting)     xos_remove_ticker_event((void *)timer, pw);
  timer_waiting = 0;
  if (callback_waiting)  xos_remove_call_back((void *)callback, pw);
  callback_waiting = 0;
  server_stop();
  return 0;
}

#endif
