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

#include "kernel.h"

#include "upcall.h"
#include "buffer.h"

#include "pinboard.h"
#include "base.h"

/* we aren't interested in Pipe updates.  These files won't be on the Pinboard.
   Monitoring causes a deadlock with WimpMon which uses pipes to communicate wimp events
   from a filter to itself - pinboard generates a wimp event when the pipe fills which causes
   a pipe fill which causes a wimp event.... */

#define FS_PIPE    47
#define FS_DEVICES 53

static volatile int upcall_diskname=0;

void upcall_disable_diskname(void)
{
  upcall_diskname=1;
}

void upcall_enable_diskname(void)
{
  upcall_diskname=0;
}

static int upcall_find_disk(_kernel_swi_regs *r)
{
  if (!upcall_diskname) return 1; // pass on, not interested at present

  // absorb this one
  r->r[0]=-1;
  return 0;
}

static int upcall_file_updated(_kernel_swi_regs *r)
{
  buffer_entry *newentry;

  switch (r->r[9]) {
  case 0:
  case 1:
  case 2:
  case 3:
  case 4:
  case 7:
  case 8:
    // file info updated
    if ((r->r[8] &0xff) != FS_PIPE && (r->r[8] &0xff) != FS_DEVICES) {
      if (buffer_push(sizeof(_buffer_hdr)+sizeof(_buffer_upcall_info)+strlen((char *)r->r[1]),&newentry)) return 1;
      strcpy(newentry->data.upcall_info.path,(char *)r->r[1]);
      newentry->hdr.type=BUFFER_UPCALL_INFO;
      newentry->data.upcall_info.fsnumber=r->r[8] &0xff;
      pollword|=1;
    }
    break;
    
  case 6:
    // delete
    if ((r->r[8] &0xff) != FS_PIPE && (r->r[8] &0xff) != FS_DEVICES) {
      if (buffer_push(sizeof(_buffer_hdr)+sizeof(_buffer_upcall_delete)+strlen((char *)r->r[1]),&newentry)) return 1;
      strcpy(newentry->data.upcall_delete.path,(char *)r->r[1]);
      newentry->hdr.type=BUFFER_UPCALL_DELETE;
      newentry->data.upcall_info.fsnumber=r->r[8] &0xff;
      pollword|=1;
    }
    break;
    
  case 520:
    // rename
    // the buffer entry this time will contain both filenames in the order source/dest, both null terminated
    if ((r->r[8] &0xff) != FS_PIPE && (r->r[8] &0xff) != FS_DEVICES) {
      int size=strlen((char *)r->r[1])
        +(r->r[6]?2+strlen((char *)r->r[6]):0)
        +1
        +strlen((char *)r->r[2])
        +(r->r[7]?2+strlen((char *)r->r[7]):0)
        +1;
      if (buffer_push(sizeof(_buffer_hdr)+sizeof(_buffer_upcall_rename)+size,&newentry)) return 1;
      newentry->hdr.type=BUFFER_UPCALL_RENAME;
      newentry->data.upcall_rename.fsnumber=r->r[8] &0xff;
      if (r->r[6]) {
        sprintf(newentry->data.upcall_rename.path,"#%s:%s",(char *)r->r[6],(char *)r->r[1]);
      } else {
        strcpy(newentry->data.upcall_rename.path,(char *)r->r[1]);
      }
      if (r->r[7]) {
        sprintf(newentry->data.upcall_rename.path+1+strlen(newentry->data.upcall_rename.path),"#%s:%s",(char *)r->r[7],(char *)r->r[2]);
      } else {
        strcpy(newentry->data.upcall_rename.path+1+strlen(newentry->data.upcall_rename.path),(char *)r->r[2]);
      }
      
      pollword|=1;
    }
    break;
    
  default:
    break;
  }
  
  return 1;
}


int upcall_handler(_kernel_swi_regs *r,void *pw)
{
  IGNORE(pw);

  if (taskhandle==0) return 1; // not running, so skip

  switch (r->r[0]) {
    case 1:
    case 2:
      return upcall_find_disk(r);

    case 3:
      return upcall_file_updated(r);
    
    default:
      return 1;
  }
}
