#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/times.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>

#include "riscos.h"
#include "module-wimp.h"
#include "module-utility.h"

void Wimp::Initialise (void)
{
  current_slot = memc->memory_size - 0x8000;
  next_slot = 0;
}

bool Wimp::SWI (unsigned int swinum, bool xbit)
{
  switch (swinum)
    {
    case Wimp_SlotSize: SlotSize (); break;
    case Wimp_ReadSysInfo: ReadSysInfo (); break;
    default:
      return false;
      break;
    }
  return true;
}

void Wimp::SlotSize (void)
{
  unsigned int cslot = READ_REG (0);
  unsigned int nslot = READ_REG (1);

  //printf ("Wimp_SlotSize: current=%08x, next=%08x\n", cslot, nslot);

  // MemoryLimit should be changed to new size of current slot
  if (cslot != 0xffffffff)
    {
      // We must preserve R3
      uint32_t r3 = READ_REG (3);

      current_slot = cslot;
      // Read existing ApplicationLimit and MemoryLimit values
      WRITE_REG (0, ENVH_MEMORYLIMIT);
      WRITE_REG (1, 0);
      riscos->SWI (OS_ChangeEnvironment);
      unsigned int memlimit = READ_REG (0);

      WRITE_REG (0, ENVH_APPLICATION_SPACE);
      WRITE_REG (1, 0);
      riscos->SWI (OS_ChangeEnvironment);
      unsigned int appspace = READ_REG (0);

      WRITE_REG (0, ENVH_MEMORYLIMIT);
      WRITE_REG (1, cslot);
      WRITE_REG (2, 0);
      WRITE_REG (3, 0);
      riscos->SWI (OS_ChangeEnvironment);

      // ApplicationLimit will also be changed if it is less than
      // MemoryLimit.
      if (appspace < memlimit)
	{
	  WRITE_REG (0, ENVH_APPLICATION_SPACE);
	  WRITE_REG (1, cslot);
	  WRITE_REG (2, 0);
	  WRITE_REG (3, 0);
	  riscos->SWI (OS_ChangeEnvironment);
	}

      memc->Resize (MEMC_CHUNK_APP, cslot);

      WRITE_REG (3, r3);
    }

  if (nslot != 0xffffffff)
    next_slot = nslot;
  
  WRITE_REG (0, current_slot);
  WRITE_REG (1, next_slot);

  // Calculate free pool
  WRITE_REG (2, memc->memory_size - (current_slot + next_slot));
}

void Wimp::ReadSysInfo (void)
{
  uint32_t r0 = READ_REG (0);
  if (r0 == 0) // Number of active tasks
    WRITE_REG (0, 0); // Program hasn't called Wimp_INitialise
  else if (r0 == 1) // Current WIMP mode
    WRITE_REG (0, 15);
  else if (r0 == 3) // Current environment
    WRITE_REG (0, 0); // We always say we are in commands (SHellCLI) mode
  else if (r0 == 4) // Text direction
    WRITE_REG (0, 0); // Left to right text entry
}
