/* wined.c */
/* Main task handling bits */

#include "common.h"

#include "kernel.h"

#include "DeskLib:Hourglass.h"
#include "DeskLib:Kbd.h"
#include "DeskLib:KernelSWIs.h"
#include "DeskLib:KeyCodes.h"
#include "DeskLib:Resource.h"
#include "DeskLib:SWI.h"
#include "DeskLib:Time.h"

#include "browser.h"
#include "choices.h"
#include "datatrans.h"
#include "deskfont.h"
#include "globals.h"
#include "monitor.h"
#include "picker.h"
#include "uri.h"
#include "usersprt.h"
#include "version.h"

#ifdef HAVE_MEMCHECK
#include "MemCheck:MemCheck.h"
#endif

extern void __heap_checking_on_all_allocates(int);
extern void __heap_checking_on_all_deallocates(int);

/* --------------------- Definitions ------------------------------ */

/* ProgInfo icons */
#define proginfo_VERSION 0
#define proginfo_USER 1
#define proginfo_EMAIL 10
#define proginfo_WEB 11

#ifndef SWI_TaskManager_EnumerateTasks
#define SWI_TaskManager_EnumerateTasks 0x42681
#endif
typedef struct {
  task_handle handle;
  char *name;
  int size;
  int flags;
} taskmanager_data;

/* ------------------ Globals not used elsewhere ------------------ */

/* Icon bar menu */
static menu_ptr iconbar_menu;
#define ibmenu_INFO 0
#define ibmenu_PICKER 1
#define ibmenu_MONITOR 2
#define ibmenu_CHOICES 3
#define ibmenu_CLEARSPR 4
#define ibmenu_QUIT 5

/* Whether templates file is open */
static BOOL wined_templatesopen;

/* ProgInfo window */
window_handle proginfo_window;


/* -------------------- List of functions ------------------------- */

/* Initialise ProgInfo dialogue box and its handlers */
window_handle proginfo_init(void);

/* Initialise wined; maxmem is max memory size to use for DA in 4K blocks */
void wined_initialise(int maxmem);

/* Handlers for icon bar icon */
BOOL iconbar_click(event_pollblock *event,void *ref);
BOOL load_handler(event_pollblock *event,void *ref);
BOOL iconbar_dataopen(event_pollblock *event,void *ref);

/* Handler for icon bar menu */
BOOL iconbar_menuclick(event_pollblock *event,void *ref);

/* Remove iconbar menu handlers */
BOOL iconbar_closemenu(event_pollblock *event,void *ref);

/* Respond to save events (loading from another app) */
BOOL save_handler(event_pollblock *event,void *reference);

/* exit(0) when message_QUIT received */
BOOL wined_quitter(event_pollblock *event,void *reference);

/* Attempt to ensure iconise protocol works correctly */
BOOL wined_ignore_ic(event_pollblock *event,void *reference);

/* Title to use for errors */
extern char error_title[40];

/* Close Messages file */
void wined_closemessages(void);


/* ---------------------------------------------------------------- */

#ifdef SHAREWARE
void banner_check(char *username)
{
  char filename[64];
  int size;
  int *checksum = 0;
  int sumcheck = 0;
  char *name;
  char ch;
  int i;
  int len = 0;
  _kernel_osfile_block osf;

  sprintf(filename,"%sUser",resource_pathname);
  if (_kernel_osfile(17, filename, &osf) == 1)
    size = osf.start;
  else
  {
    MsgTrans_Lookup(messages,"Unreg",username,40);
    return;
  }
  if (size >= 6)
  {
    checksum = malloc(size);
    if (!checksum)
      MsgTrans_Report(0,"NoStore",TRUE);
    Error_CheckFatal(File_LoadTo(filename,checksum,&size));
    if (checksum[0])
    {
      name = ((char *) checksum) + 4;
      len = 0;
    }
    else
    {
      len = checksum[1];
      name = ((char *) checksum) + 12;
      checksum += 2;
      size -= 8;
    }
/*fprintf(stderr, "Checksum : %x\n", *checksum);
fprintf(stderr, "len = %d, size = %d\n", len, size);*/
    i = 0;
    do
    {
      ch = name[i];
      if (len || ch)
      {
        ch ^= (65 + 0x65 * i);
        sumcheck = ((sumcheck << 5) + (sumcheck >> 27)) ^ ch;
      }
      username[i] = ch;
/*fprintf(stderr, "%c\t%d\t%x\n", ch, ch ^ (65 + 0x65 * i), sumcheck);*/
      i++;
    } while ((len ? i < len : ch != 0) && i <= size - 4);
    username[i] = 0;
  }
  if (size < 6 || sumcheck != *checksum)
  {
    os_error illegal;
    MsgTrans_Lookup(messages,"Unreg",username,40);
    illegal.errnum = 0;
    MsgTrans_Lookup(messages, "Illegal", illegal.errmess, 252);
    if (ok_report(&illegal))
      File_Delete(filename);
  }
  free(len ? checksum - 2 : checksum);
}
#endif /* ifdef SHAREWARE */

void wined_closemessages()
{
  MessageTrans_CloseFile(messages);
  if (wined_templatesopen)
    Wimp_CloseTemplate();
}

BOOL iconbar_click(event_pollblock *event,void *ref)
{
  switch (event->data.mouse.button.value)
  {
    case button_MENU:
      WinEd_CreateMenu(iconbar_menu,event->data.mouse.pos.x,-1);
      Event_Claim(event_MENU,event_ANY,event_ANY,iconbar_menuclick,0);
      EventMsg_Claim(message_MENUSDELETED,event_ANY,iconbar_closemenu,0);
      help_claim_menu("IBM");
      return TRUE;
    case button_SELECT:
    case button_ADJUST:
      browser_newbrowser();
      return TRUE;
    default:
      return FALSE;
  }
  return FALSE;
}

BOOL iconbar_menuclick(event_pollblock *event,void *ref)
{
  mouse_block ptrinfo;

  Wimp_GetPointerInfo(&ptrinfo);

  switch (event->data.selection[0])
  {
    case ibmenu_INFO:
      break;
    case ibmenu_PICKER:
      picker_open();
      break;
    case ibmenu_MONITOR:
      monitor_open();
      break;
    case ibmenu_CHOICES:
      choices_open();
      break;
    case ibmenu_CLEARSPR:
      usersprt_clear();
      break;
    case ibmenu_QUIT:
      browser_preselfquit();
      break;
  }

  if (ptrinfo.button.data.adjust)
    Menu_ShowLast();

  return TRUE;
}

BOOL iconbar_closemenu(event_pollblock *event,void *reference)
{
  Event_Release(event_MENU,event_ANY,event_ANY,iconbar_menuclick,0);
  EventMsg_Release(message_MENUSDELETED,event_ANY,iconbar_closemenu);
  help_release_menu();
  return TRUE;
}

BOOL load_handler(event_pollblock *event,void *ref)
{
  if (event->data.message.data.dataload.filetype == filetype_TEMPLATE &&
  	event->data.message.data.dataload.window == window_ICONBAR)
    datatrans_load(event,browser_load,NULL);
  else if (event->data.message.data.dataload.filetype == FILETYPE_Sprites)
  {
    if (Kbd_KeyDown(inkey_SHIFT))
    {
      /* Merge file with Wimp pool and redraw whole screen */
      int r[10];
      window_redrawblock redraw;

      r[0] = 11;
      r[2] = (int) event->data.message.data.dataload.filename;
      if (!Error_Check(Wimp_SpriteOp(r)))
      {
        Screen_CacheModeInfo();
        redraw.window = -1;
        redraw.rect.min.x = redraw.rect.min.y = 0;
        redraw.rect.max = screen_size;
        Wimp_ForceRedraw(&redraw);
      }
    }
    else
    {
      datatrans_load(event,usersprt_merge,NULL);
    }
  }
  return TRUE;
}

BOOL iconbar_dataopen(event_pollblock *event,void *reference)
{
  /* DataOpen is equivalent to DataLoad */
  if (event->data.message.data.dataload.filetype == filetype_TEMPLATE)
  {
    int size;

    message_block message = event->data.message;

    message.header.yourref = message.header.myref;
    message.header.action = message_DATALOADACK;
    Error_Check(Wimp_SendMessage(event_SEND,&message,
    				 event->data.message.header.sender,0));
    size = File_Size(event->data.message.data.dataload.filename);
    if (size)
      browser_load(event->data.message.data.dataload.filename,size,0);
    else
      MsgTrans_ReportPS(messages,"NotFile",FALSE,
      			event->data.message.data.dataload.filename,0,0,0);

    if (!strcmp(message.data.dataload.filename,"<Wimp$Scrap>"))
      File_Delete(message.data.dataload.filename);

    return TRUE;
  }
  return FALSE;
}

BOOL save_handler(event_pollblock *event,void *ref)
{
  if ((event->data.message.data.datasave.filetype == filetype_TEMPLATE &&
  	event->data.message.data.datasave.window == window_ICONBAR) ||
  	event->data.message.data.datasave.filetype == FILETYPE_Sprites)
    datatrans_saveack(event);
  return TRUE;
}

static BOOL proginfo_email(event_pollblock *event,void *ref)
{
  uri_send("mailto:tony@caspian.uklinux.net");
  return TRUE;
}

static BOOL proginfo_web(event_pollblock *event,void *ref)
{
  uri_send("http://www.caspian.uklinux.net/wined.html");
  return TRUE;
}

window_handle proginfo_init()
{
  window_handle proginfo;
  window_block *windef;
  char format[128];
  _kernel_swi_regs r;

  windef = templates_load("ProgInfo",0,0,0,0);
  Error_CheckFatal(Wimp_CreateWindow(windef,&proginfo));
  free(windef);

  sprintf(format,"%s (%%dy %%mo %%ce%%yr)",version);
  r.r[0] = -1;
  r.r[1] = (int) version_utc;
  r.r[2] = (int) Icon_GetTextPtr(proginfo,proginfo_VERSION);
  r.r[3] = 28;
  r.r[4] = (int) format;
  _kernel_swi(SWI_Territory_ConvertDateAndTime,&r,&r);

  Event_Claim(event_OPEN,proginfo,event_ANY,Handler_OpenWindow,0);
  Event_Claim(event_CLOSE,proginfo,event_ANY,Handler_CloseWindow,0);
  Event_Claim(event_CLICK,proginfo,proginfo_EMAIL,proginfo_email,0);
  Event_Claim(event_CLICK,proginfo,proginfo_WEB,proginfo_web,0);
  help_claim_window(proginfo,"ATP");

  return proginfo;
}

void wined_initialise(int maxmem)
{
  char buffer[256];
  int taskmanager_call;
  icon_handle baricon;
  int wined_wimpmessages[] = {message_DATALOAD,message_DATALOADACK,
                              message_DATASAVE,message_DATASAVEACK,
                              message_DATAOPEN,
                              message_PREQUIT,
                              /*message_MENUSDELETED,*/message_MENUWARN,
                              message_WINDOWINFO,
                              message_HELPREQUEST,
                              message_MODECHANGE,
                              Message_FontChanged,
                              message_URI,
                              0};
  /* message_MENUSDELETED now only generated internally to avoid confusion
     over which menu tree it's actually for */

  /* Work out whether to support nested wimp */
  SWI(1, 1, 0x400f2, 7, &taskmanager_call);
  if (taskmanager_call >= 380)
    taskmanager_call = 380;
  else
    taskmanager_call = 310;

  /* Start task and trap unhandled events */
  Event_Initialise3(APPNAME,taskmanager_call,wined_wimpmessages);
  EventMsg_Initialise();

  Resource_InitialisePath("WinEd");

  /* Load Messages file */
  sprintf(buffer,"%sMessages",resource_pathname);
  Error_CheckFatal(MsgTrans_LoadFile(&messages,buffer));
  atexit(wined_closemessages);

  /* Set up error title for subsequent non-fatal errors */
  MsgTrans_Lookup(messages,"MsgFrom:Message from WinEd",error_title,40);

  /* Check we're not already loaded */
  taskmanager_call = 0;
  do
  {
    taskmanager_data *entry,*end_of_entries;

    entry = (taskmanager_data *) buffer;
    SWI(3,2,SWI_TaskManager_EnumerateTasks,taskmanager_call,entry,256,
    	&taskmanager_call,&end_of_entries);
    while ((int) entry < (int) end_of_entries)
    {
      if (!strcmpcr(entry->name,APPNAME))
        MsgTrans_Report(messages,"Already",TRUE);
      entry++;
    }
  } while (taskmanager_call >= 0);

#ifdef CASTLE_FLEX
  flex_init("WinEd",NULL,maxmem);
#else
  if (maxmem)
    flex_initx("WinEd",NULL,TRUE,maxmem,FALSE);
  else
    flex_init("WinEd",NULL);
#endif

  /* Set up user sprite area */
  usersprt_init();

  deskfont_init();

  /* Open templates */
  sprintf(buffer,"%sTemplates",resource_pathname);
  Error_CheckFatal(Wimp_OpenTemplate(buffer));
  wined_templatesopen = TRUE;

  /* Load all windows from templates */
  proginfo_window = proginfo_init();
  browser_init();
  saveas_init();
  picker_init();
  monitor_init();
  uri_init();

  /* Close templates */
  Wimp_CloseTemplate();
  wined_templatesopen = FALSE;

  /* Icon bar menu */
  MsgTrans_Lookup(messages,"IBMenu",buffer,256);
  iconbar_menu = Menu_New(APPNAME,buffer);
  if (!iconbar_menu)
    MsgTrans_Report(messages,"NoMenu",TRUE);
  Menu_AddSubMenu(iconbar_menu,ibmenu_INFO,(menu_ptr) proginfo_window);

  /* Put icon on icon bar */
  baricon = Icon_BarIcon("!wined",iconbar_RIGHT);
  Event_Claim(event_CLICK,window_ICONBAR,baricon,iconbar_click,0);
  EventMsg_Claim(message_DATALOAD,event_ANY,load_handler,0);
  EventMsg_Claim(message_DATAOPEN,window_ICONBAR,iconbar_dataopen,0);
  EventMsg_Claim(message_DATASAVE,event_ANY,save_handler,0);
  help_claim_window(window_ICONBAR,"IBI");

  EventMsg_Claim(message_QUIT,event_ANY,wined_quitter,0);
  EventMsg_Claim(message_WINDOWINFO,event_ANY,wined_ignore_ic,0);
}

BOOL wined_quitter(event_pollblock *event,void *reference)
{
  browser_userquit = TRUE;
  exit(0);
  return TRUE;
}

BOOL wined_ignore_ic(event_pollblock *event,void *reference)
{
  return TRUE;
}

int main(int argc,char **argv)
{
/*
  __heap_checking_on_all_allocates(1);
  __heap_checking_on_all_deallocates(1);
*/
#ifdef HAVE_MEMCHECK
  fprintf(stderr, "Enabling MemCheck\n");
  MemCheck_Init();
  MemCheck_RegisterArgs(argc, argv);
  MemCheck_InterceptSCLStringFunctions();
#endif
  Hourglass_On();

  /* Disable MemCheck for initialisation to prevent stderr clutter
     caused by badly written but harmless DeskLib/Resource code */
#ifdef HAVE_MEMCHECK
  MemCheck_SetReadChecking(0);
#endif
  wined_initialise(atoi(argv[1])*1024);
#ifdef HAVE_MEMCHECK
  MemCheck_SetReadChecking(1);
#endif

  /* Check whether to load file straight away */
  if (argc == 3)
    browser_load(argv[2],File_Size(argv[2]),0);

#ifdef SHAREWARE
  /* Check for registration */
  banner_check((char *) Icon_GetTextPtr(proginfo_window,proginfo_USER));
#endif

  Hourglass_Off();

  while (TRUE)
  {
    if (monitor_isactive)
    {
      Wimp_PollIdle(event_mask, &event_lastevent, Time_Monotonic()+25);
    }
    else
    {
      Wimp_Poll(event_mask, &event_lastevent);
    }
    if (event_lastevent.type <= 19 && event_lastevent.type >= 0)
      Event_Process(&event_lastevent);
  }
}

