/* Original code (c) Acorn Computers Ltd, 1992-3 */

/* $Id: c.filer 3.1 93/03/09 20:00:45 brian Exp $ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kernel.h"
#include "swis.h"
#include "ModuleWrap.h"
#include "util.h"
#include "cstart.h"
#include "wimp.h"

#define RUNNABLE        /* to enable direct running */

#define TASK    ('K'<<24|'S'<<16|'A'<<8|'T')

int             taskhandle;
int             taskstack;

static int      filertaskhandle;
static char FilerName[]= FS"FSFiler";

/* Define TRACESERVICE in order to output trace of service calls */
/* #define TRACESERVICE */

static void removetask(void)
{
        _kernel_swi_regs r;

        r.r[0]=taskhandle;
        r.r[1]=TASK;
        taskhandle=0;
        if (r.r[0] && r.r[0]!=-1)
          _kernel_swi( XOS_Bit | Wimp_CloseDown , &r, &r );
        if (taskstack)
          free((char *)taskstack);
        taskstack=0;
}

/*
        This is the finalisation code
*/

static void fs_finalise
( void )
{ removetask();
}

/*
        This is the initialisation code
*/
_kernel_oserror *fs_initialise
(
        char *cmd_tail,
        int podule_base,
        void *private_word
)
{
        _kernel_oserror *err=NULL;

        private_word=private_word;
        /*
                These keep the compiler quiet.
        */
        cmd_tail = cmd_tail;
        podule_base = podule_base;

        /*
                Must record fact filer task is not running
        */
        taskhandle = 0;
        taskstack = 0 ; /* and that its stack is not yet allocated */

        atexit( fs_finalise );

        return err;
}

/*
        Service call handler
*/

#ifdef TRACESERVICE
static struct {int svc; char *name;} svcs[] =
{
 {0x00,"Serviced"},
 {0x04,"UKCommand"},
 {0x06,"Error"},
 {0x07,"UKByte"},
 {0x08,"UKWord"},
 {0x09,"Help"},
 {0x0b,"ReleaseFIQ"},
 {0x0c,"ClaimFIQ"},
 {0x11,"Memory"},
 {0x12,"StartUpFS"},
 {0x27,"Reset"},
 {0x28,"UKConfig"},
 {0x29,"UKStatus"},
 {0x2a,"NewApplication"},
 {0x40,"FSRedclare"},
 {0x41,"Print"},
 {0x42,"LookupFileType"},
 {0x43,"International"},
 {0x44,"Keyhandler"},
 {0x45,"PreReset"},
 {0x46,"ModeChange"},
 {0x47,"ClaimFIQinBackground"},
 {0x48,"ReAllocatePorts"},
 {0x49,"StartWimp"},
 {0x4a,"StartedWimp"},
 {0x4b,"StartFiler"},
 {0x4c,"StartedFiler"},
 {0x4d,"PreModeChange"},
 {0x4e,"MemoryMoved"},
 {0x4f,"FilerDying"},
 {0x50,"ModeExtension"},
 {0x51,"ModeTranslation"},
 {0x52,"MouseTrap"},
 {0x53,"WimpCloseDown"},
 {0x54,"Sound"},
 {0x55,"NetFS"},
 {0x56,"EconetDying"},
 {0x57,"WimpReportError"},
 {-1,"Something else"}
};
#endif

void fs_service
(
        int service_number,
        _kernel_swi_regs *r,
        void *private_word
)
{
#ifdef TRACESERVICE
{ int i;
 for (i=0;svcs[i].svc>=0;i++) if (svcs[i].svc==service_number)break;
 printf("Service_%s (%#x)%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\r\n",svcs[i].name,service_number,*r);
}
#endif
        private_word=private_word;
        switch( service_number )
        {
        case Service_StartFiler:
          if (!taskhandle)
          {
            filertaskhandle=r->r[0];
            taskhandle=-1; /* attempting start flag */
            r->r[0]=(int)("Desktop_"FS"FSFiler");
            r->r[1]=0;
          }
          break;
        case Service_StartedFiler:
          if (taskhandle==-1)
            taskhandle=0;
          break;
        case Service_Reset:
          taskhandle=0;
          break;
        case Service_FilerDying:
          removetask();
          break;

        /*
                Handle other service calls here
        */
        }
}

/*
        command processor
*/
_kernel_oserror *fs_command
(
        char *arg_string,
        int argc,
        int cmd_no,
        void *private_word
)
{
        _kernel_swi_regs r;
#define My_Command_Parameter_Buffer_Len 256
static  char my_command_parameter_buffer[ My_Command_Parameter_Buffer_Len ];
        char *temptr = my_command_parameter_buffer;

        argc = argc;
        private_word = private_word;

        /*
                Change the control character terminator to a nul terminator
        */
        for ( ; temptr - my_command_parameter_buffer < My_Command_Parameter_Buffer_Len && *arg_string >= ' ' ; )
        {
                *temptr++ = *arg_string++;
        }

        *temptr = '\0';

        arg_string = my_command_parameter_buffer;

        /*
                Switch between the commands
        */
        switch ( cmd_no )
        {
        case 0: /*      *Desktop_FSnameFSFiler */
                if (taskhandle!=-1)
                {
#ifndef RUNNABLE
                  printf("Use *Desktop to start %s\n",FilerName);
                  return NULL;
#else
                  removetask();
                  taskhandle=-1;
#endif
                }
                r.r[0] = OSModule_Enter;
                r.r[1] = (int)FilerName;
                r.r[2] = (int)arg_string;
                return _kernel_swi( XOS_Bit | OS_Module, &r, &r );
        default:
                return NULL;
        }
}

int filertask( char *cmdtail );

#define MENUDEPTH 2

static struct
{ wimp_menuhdr hdr;
  wimp_menuitem item[MENUDEPTH];
} mymenu=
{ { "Menutitle", 7, 2, 7, 0, 96, 44, 0 },
  { {
      0
        , (wimp_menuptr)-1, wimp_ITEXT |
                         wimp_IBTYPE*wimp_BNOTIFY |
                         wimp_IFORECOL*7 |
                         wimp_IBACKCOL*0, "Free" },
    { wimp_MLAST
        , (wimp_menuptr)-1, wimp_ITEXT |
                         wimp_IBTYPE*wimp_BNOTIFY |
                         wimp_IFORECOL*7 |
                         wimp_IBACKCOL*0, "Quit" }
} } ;

int filertask
( char *cmdtail )
{
  _kernel_swi_regs r;
  os_error *err;
  wimp_icreate wi;
  wimp_i icon;
  wimp_eventstr ev;
  int wimpversion;
  int maydataload=0;
#ifndef RUNNABLE
  if (taskhandle!=-1)
    return 0;
#endif
  cmdtail=cmdtail; /* Use it to scare off warnings */
  r.r[0]=200;
  r.r[1]=TASK;
  r.r[2]=(int)FilerName;
  err=(os_error *)_kernel_swi( Wimp_Initialise, &r, &r );
/*  err=wimp_taskinit( FilerName, (wimp_t*)&taskhandle ); */
  if (err)
    goto error;
  wimpversion=r.r[0];
  taskhandle=r.r[1];
  if (wimpversion>200)
    wi.w=-6, r.r[0]=0x40000000;
  else
    wi.w=-2;
  wi.i.box.x0=0;
  wi.i.box.y0=-16; /* base of text, 32 high */
  wi.i.box.x1=2*sprx;
  wi.i.box.y1=-16+32+4+4*spry;
  wi.i.flags=wimp_ITEXT |
             wimp_ISPRITE |
             wimp_IHCENTRE |
             wimp_INDIRECT |
             wimp_IBTYPE*wimp_BCLICKDEBOUNCE |
             wimp_IFORECOL*7 |
             wimp_IBACKCOL*1 ;
  wi.i.data.indirecttext.buffer=FS;
  wi.i.data.indirecttext.validstring=validstr;
  wi.i.data.indirecttext.bufflen=3;
  r.r[1]=(int)&wi;
  err=(os_error *)_kernel_swi( Wimp_CreateIcon, &r, &r );
  icon=r.r[0];
  /* err=wimp_create_icon(&wi,&icon); */
  if (err)
    goto error;
  for (;;)
  {
    maydataload = 0;
pol:err=wimp_poll(wimp_EMNULL,&ev);
    if (err)
      goto error;
    switch (ev.e)
    {
    case wimp_EBUT:
      switch (ev.data.but.m.bbits)
      {
      case wimp_BLEFT:
      case wimp_BRIGHT:
        ev.data.msg.hdr.size=sizeof(wimp_msghdr)+sizeof(int)*2+(strlen(RootName)&~3)+4;
        ev.data.msg.hdr.your_ref=0;
        ev.data.msg.hdr.action=wimp_FilerOpenDir;
        ev.data.msg.data.words[0]=FilingSystemNumber;
        ev.data.msg.data.words[1]=0;
        strcpy((char *)&ev.data.msg.data.words[2],
                                ev.data.but.m.bbits==wimp_BLEFT?RootName:RootName1 );
        err=wimp_sendmessage(wimp_ESEND,&ev.data.msg,(wimp_t)filertaskhandle);
        if (err)
          goto error;
        continue;
      case wimp_BMID:
        strcpy(mymenu.hdr.title,FS"FS");
        err=wimp_create_menu((wimp_menustr *)&mymenu,ev.data.but.m.x-64,96+MENUDEPTH*44);
        if (err)
          goto error;
        continue;
      }
      break;
    case wimp_EMENU:
      switch (ev.data.menu[0])
      {
      case 0: /* Free */
        if (_kernel_oscli("ShowFree -fs "FS" "DISK)==_kernel_ERROR)
          _kernel_oscli("WimpTask "FS":Free "DISK);
        continue;
      case 1: /* Quit */
        r.r[0]=17;
        r.r[1]=(int)&RootName;
        if (quitmsg[0] && !_kernel_swi( OS_File, &r, &r ) && r.r[4] )
        { r.r[0]=(int)&quitmsg;
          r.r[1]=3+(1<<4);
          r.r[2]=(int)FilerName;
          err=(os_error *)_kernel_swi( Wimp_ReportError, &r, &r );
          if (r.r[1]!=1)
            continue;
        }
        _kernel_oscli("RMKill "FS"FS");
#ifdef KILLCMD1
        _kernel_oscli(KILLCMD1);
#endif
        r.r[0]=3;
        r.r[1]=-4<<20;
        _kernel_swi( OS_ChangeDynamicArea, &r, &r );
        r.r[0]=0;
        r.r[3]=(int)&FilerName;
        _kernel_swi( OS_ExitAndDie, &r, &r );
      }
      break;
    case wimp_ESEND: case wimp_ESENDWANTACK:
      switch (ev.data.msg.hdr.action)
      { char buf[256];
      case wimp_MCLOSEDOWN:
        break;
      case wimp_MDATASAVE:
        strcpy(buf,RootName); strcat(buf,"."); strcat(buf,ev.data.msg.data.datasaveok.name);
        strcpy(ev.data.msg.data.datasaveok.name,buf);
        ev.data.msg.hdr.size = (strlen(ev.data.msg.data.datasaveok.name)|3)+1+44;
        ev.data.msg.hdr.your_ref = ev.data.msg.hdr.my_ref;
        ev.data.msg.hdr.action = wimp_MDATASAVEOK;
        wimp_sendmessage(wimp_ESEND,&ev.data.msg,ev.data.msg.hdr.task);
        maydataload = 1;
        goto pol;
      case wimp_MDATALOAD:
        if (maydataload)
        { ev.data.msg.hdr.your_ref = ev.data.msg.hdr.my_ref;
          ev.data.msg.hdr.action = wimp_MDATALOADOK;
          wimp_sendmessage(wimp_ESEND,&ev.data.msg,ev.data.msg.hdr.task);
          maydataload = 0;
        }
        continue;
      default:
        continue;
      }
      break;
    default:
      continue;
    }
    break;
  }
  return 0;
error:
  wimp_reporterror(err,0, FilerName);
  return (int)err;
}
