/* read.c */

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

#include "colourdbox.h"
#include "colourmenu.h"
#include "event.h"
#include "fontdbox.h"
#include "fontmenu.h"
#include "saveas.h"
#include "scale.h"
#include "toolbox.h"
#include "wimplib.h"
#include "window.h"

#include "error.h"

#include "dboxtools.h"
#include "read.h"

#define IBUFF_SIZE 10

#define ColourDbox 0x829c0
#define ColourMenu 0x82980
#define DCS        0x82a80
#define FileInfo   0x82ac0
#define FontDbox   0x82a00
#define FontMenu   0x82a40
#define Iconbar    0x82900
#define Menu       0x828c0
#define ProgInfo   0x82b40
#define Quit       0x82a90
#define SaveAs     0x82bc0
#define Scale      0x82c00
#define Window     0x82890

typedef struct Pending
{ int reference;
  PendingHandler handler;
  void *handle;
  ComponentId component;
} Pending;

_kernel_oserror *read_object
( ObjectId object, char *buffer, int size)
{ int class, nbytes, flags, value;
  int iBuffer[IBUFF_SIZE];
  _kernel_oserror *er = NULL;
  
  NER( toolbox_get_object_class( 0, object, &class ));
  switch( class )
  { case ColourDbox:
      NER( colourdbox_get_colour
             ( 0, object, iBuffer, IBUFF_SIZE, &flags, &nbytes));
      if( flags & 1 ) *iBuffer = 1;
      sprintf( buffer, "%x", *iBuffer );
      break;

    case ColourMenu:
      NER( colourmenu_get_colour( 0, object, &value ));
      sprintf( buffer, "%i", value );
      break;

    case FontDbox:
      NER( fontdbox_get_font( 0, object, buffer, size, &nbytes));
      break;

    case FontMenu:
      NER( fontmenu_get_font( 0, object, buffer, size, &nbytes));
      break;

    case SaveAs:
      NER( saveas_get_file_name( 0, object, buffer, size, &nbytes));
      break;

    case Scale:
      NER( scale_get_value( 0, object, &value ));
      sprintf( buffer, "%i", value );
      break;

    case Window:
    case Quit:
    case ProgInfo:
    case Menu:
    case Iconbar:
    case FileInfo:
    case DCS:
      sprintf
      ( error_block.errmess, "Object class %i can not return a value", class );
      error_block.errnum = ERROR_CLASS_NO_VALUE;
      error_displayRet( &error_block );
      *buffer = 0;
      break;

    default:
      sprintf( error_block.errmess, "Object class %i not understood", class );
      error_block.errnum = ERROR_CLASS_NOT_UNDERSTOOD;
      error_displayRet( &error_block );
      *buffer = 0;
      break;
  }
  return er;
}

_kernel_oserror *read_gadget
( ObjectId object, ComponentId component, char *buffer, int size)
{ int type, state, nbytes, value;
  ComponentId selected;
  _kernel_oserror *er = NULL;

  if( component == -1 ) /* no component, so read the object */
    return read_object( object, buffer, size);
    
  er = gadget_get_type( 0, object, component, &type );
  if( er ) return er;
  switch( type )
  { case 192: /* Option Button  */
      er = optionbutton_get_state( 0, object, component, &state );
      if( !er  ) sprintf( buffer, "%i", state );
      break;    
      
    case 384: /* Radio Button   */
      er = radiobutton_get_state ( 0, object, component, &state, &selected );
      if( !er ) sprintf( buffer, "%i", state );
      break;
            
    case 448: /* Display Field  */
      er = displayfield_get_value
           ( 0, object, component, buffer, size, &nbytes );
      break;
      
    case 512: /* Writable Field */
      er = writablefield_get_value
           ( 0, object, component, buffer, size, &nbytes );
      break;
    
    case 576: /* Slider         */
      er = slider_get_value ( 0, object, component, &value );
      if( !er ) sprintf( buffer, "%i", value );
      break;
      
    case 832: /* Number Range   */
      er = numberrange_get_value( 0, object, component, &value );
      if( !er ) sprintf( buffer, "%i", value );
      break;
      
    case 896: /* String Set     */
      er = stringset_get_selected
           ( 0, object, component, buffer, size, &nbytes );
      break;

    case 128: /* Action Button  */
    case 256: /* Labelled Box   */
    case 320: /* Label          */
    case 640: /* Draggable      */
    case 704: /* Pop Up Menu    */
    case 768: /* Adjuster Arrow */
    case 960: /* Button         */
      sprintf
      ( error_block.errmess, "Component type %i can not return a value", type );
      error_block.errnum = ERROR_GADGET_NO_VALUE;
      er = &error_block;
      *buffer = 0;
      break;
         
    default:
      sprintf( error_block.errmess, "Component type %i not understood", type );
      error_block.errnum = ERROR_GADGET_NOT_UNDERSTOOD;
      er = &error_block;
      *buffer = 0;
      break;
  }
  return er;
}

_kernel_oserror *read_event
( int ec, WimpPollBlock *wpb, ComponentId c, char *buffer, int space,
  int *pending, PendingHandler p, void *handle)
{ switch( ec )
  { case 0x200:
      return
        read_toolbox( ec, (ToolboxEvent *) wpb, c, buffer, space );

    case 17:
    case 18:
    case 19:
      return read_message( (WimpMessage *) wpb, c, buffer, space,
                           pending, p, handle);

    default:
      error( "Not yet implemented in read_event()" );
  }
  return NULL;
}

_kernel_oserror *read_toolbox
( int ec, ToolboxEvent *e, ComponentId c, char *buffer, int space)
{ _kernel_oserror *er = NULL;

  switch( ec )
  { case 0x82881: /* ActionButton_Selected */
      if( space < 2 )
      { strcpy( error_block.errmess, "read_toolbox() buffer too small");
        error_block.errnum = ERROR_BUFFER_OVERFLOW;
        return &error_block;
      }
      else
        sprintf( buffer, "%i", e->hdr.flags & 3 );
      break;
      
    default:
      *buffer = 0;
      break;
  }
  return er;    
}

static int dataLoad( WimpMessage *message, void *handle )
{ Pending *p = (Pending *) handle;

  if( p->reference != message->hdr.your_ref ) return 0; /* wrong one */
  switch( p->component )
  { case 4:
    case 5:
      p->handler( p->handle, 17, (WimpPollBlock *) message );
      break;

    default:
      error("dataLoad().  Unexpected component id");
      break;
  }
  event_deregister_message_handler( 3, dataLoad, p );
  return 0;             
}

static char tooSmall[] = "read_message() buffer too small";

#define CHECK_SPACE(need) if((need)>space){strcpy(error_block.errmess,tooSmall);error_block.errnum=ERROR_BUFFER_OVERFLOW;return &error_block;}

_kernel_oserror *read_message
( WimpMessage *message, ComponentId c, char *buffer, int space,
  int *pending, PendingHandler p, void *handle )
{ _kernel_oserror *er = NULL;
  _kernel_swi_regs regs;
  Pending *pen;
  int th;
  static int currentReference = 0; /* ref of last created message sequence */
  
  switch( message->hdr.action_code )
  { case 1: /* data */
      switch( c )
      { case 1: /* hex filetype */
          CHECK_SPACE(4)
          sprintf( buffer, "%03x", message->data.data_save.file_type);
          break;
          
        case 2: /* text filetype */
          CHECK_SPACE(8)
          regs.r[0] = 18;
          regs.r[2] = message->data.data_save.file_type;
          er = _kernel_swi( 0x29, &regs, &regs ); /* OS_FSControl */
          if( er ) return er;
          regs.r[4] = 0;
          strcpy( buffer, (char *) &regs.r[2] );
          break;

        case 3: /* leafname */ 
          CHECK_SPACE(strlen(message->data.data_load.leaf_name)+1)
          strcpy( buffer, message->data.data_load.leaf_name);
          break;
          
        case 4: /* pending, full pathname */
        case 5: /* pending, contents of file */
          if( currentReference != message->hdr.my_ref && p )
          /* check that a pending operation has not already been set up
             and that the client has provided a pending handler */
          { if( pending ) *pending = TRUE;
            pen = malloc( sizeof( Pending ));
            if( pen == NULL )
            { strcpy( error_block.errmess, "Out of memory" );
              error_block.errnum = ERROR_OUT_OF_MEMORY;
              return &error_block;
            }
            pen->handle = handle;
            pen->handler = p;
            pen->component = c;
            message->hdr.your_ref = pen->reference = message->hdr.my_ref;
            strcpy( message->data.data_save_ack.leaf_name, "<Wimp$Scrap>" );
            message->data.data_save_ack.estimated_size = -1;
            wimp_send_message( 17, message, message->hdr.sender, -1, &th );
            event_register_message_handler( 3, dataLoad, pen );
            currentReference = message->hdr.my_ref;
          }               
          break;
      }

    case 3: /* Message_DataLoad */
      switch( c )
      { case 4: /* full pathname */
          CHECK_SPACE(strlen(message->data.data_save.leaf_name)+1)
          strcpy( buffer, message->data.data_load.leaf_name);
          break;
          
        case 5: /* contents of file */
          error( "dataLoad component 5 not yet implemented" );
          break;
          
        case 6: /* contents of file placed in a buffer */
          error( "dataLoad component 6 not yet implemented" );
          break;
      }  
  }
  return er;
}

/* end of read.c */
