/* dboxtools:h.action */

#include <stdlib.h>

#include "window.h"

#include "error.h"
#include "clibExtra.h"

#include "action.h"
#include "dboxtools.h"
#include "debug.h"
#include "strbuild.h"
#include "find.h"
#include "list.h"
#include "main.h"
#include "null.h"
#include "read.h"
#include "write.h"

#include "er.h"

#define BUFF_SIZE 1000

enum ObjectListAction { ListNull, Hide, Show, Fade, Unfade };
static char *ListAction[] = { "Null", "Hide", "Show", "Fade", "Unfade" };

typedef struct ActionPending
{ Action action;
  IdBlock id;
} ActionPending;

static ActionPending a;
static ActionPending *ap = &a;
  
static void pendingHandler( void *handle, int event, WimpPollBlock *wpb )
{ ActionPending *ap = (ActionPending *) handle;

  action( &ap->action, &ap->id, event, wpb );
  free( ap );
}

static _kernel_oserror *actOnListOfItems
(enum ObjectListAction act, char *list, char terminator, IdBlock *id)
{ ObjectId o;
  ComponentId c;
  _kernel_oserror *er = NULL;
  unsigned int flags;
  char rangeType;

  er = listItem( list, terminator, &o, &c, &rangeType );
  while( (o != -1 || c != -1) && !er )
  { if( debug )
    { fprintf( debug, "Action %s on %x:%x", ListAction[act], o, c );
      fflush( debug );
    }

    switch( act )
    { case Hide:
        er = toolbox_hide_object( 0, o );
        break;
  
      case Show:
        er = toolbox_show_object( 0, o, 0, NULL, id->self_id,
                                                 id->self_component );
        break;
        
      case Fade:
        er = gadget_get_flags( 0, o, c, &flags );
        if( er ) return er;
        er = gadget_set_flags( 0, o, c, (1u << 31 ) | flags );
        break;
        
      case Unfade:
        er = gadget_get_flags( 0, o, c, &flags );
        if( er ) return er;
        er = gadget_set_flags( 0, o, c, ~(1u << 31 ) & flags );
        if( er ) return er;
        break;
    }
    er = listItem( NULL, terminator, &o, &c, &rangeType );
  }
  return er;    
}

int action( Action *a, IdBlock *id, int event, WimpPollBlock *wpb )
{ int i, finished = 0, pending = 0;
  char buffer[BUFF_SIZE];
  _kernel_oserror *er = NULL;
  _kernel_swi_regs regs;
  ObjectId o;
  ComponentId c;
  
  if( debug )
  { fputs( "\n\nExecuting", debug );
    debug_action( a );
    fputs( "", debug );
  }
    
  switch( a->action )
  { /* Program control */
    case 'Q': /* Quit */
      exit( 0 );
      break;
      
    case 'H': /* Hide */
      er = actOnListOfItems( Hide, a->arg[0], 0, id );
      break;
      
    case 'W': /* shoW   */
      er = actOnListOfItems( Show, a->arg[0], 0, id );
      break;
      
    case 'N': /* No more */
      finished = 1;
      break;
      
    /* String building */
    case 'C': /* Command  */
      er=strbuild_build(a->arg[0], buffer, BUFF_SIZE, a, event, wpb, &pending, pendingHandler, ap );
      if( debug )
      { if( pending ) fputs( "Pending ", debug );
        fprintf( debug, "Command %s\n", buffer );
        fflush( debug );
      }
      if( !pending && !er )
      {
        regs.r[0] = (int) buffer;
        er = _kernel_swi( 5, &regs, &regs ); /* OS_CLI */
      }   
      break;
      
    case 'K': /* Keyboard */
      er=strbuild_build(a->arg[0], buffer, BUFF_SIZE, a, event, wpb, &pending, pendingHandler, ap );
      if( debug )
      { if( pending ) fputs( "Pending ", debug );
        fprintf( debug, "Keyboard %s\n", buffer );
        fflush( debug );
      }
      if( !pending && !er )
      { /* keyboard stuff needed here ********/
      }
      break;
      
    /* Fades */
    case 'F': /* Fade */
      er = actOnListOfItems( Fade, a->arg[0], 0, id);
      break;    

    case 'U': /* Unfade */
      er = actOnListOfItems( Unfade, a->arg[0], 0, id);
      break;
          
    /* Equals */
    case 'E': /* Equals */
      er=strbuild_build(a->arg[1], buffer, BUFF_SIZE, a, event, wpb,
                        &pending, pendingHandler, ap  );
      if( debug )
      { if( pending ) fputs( "Pending ", debug );
        fprintf( debug, "%x:%x Equals %s\n", a->object, a->component, buffer);
        fflush( debug );
      }
      if( !pending && !er )
      { find_objectAndComponent( a->arg[0], &o, &c );
        if( o == -1 ) defError( 6, a->line, -1 );
        write_gadget( o, c, buffer );
      }
      break;

    /* Input/output */
    /* case 'I': */ /* Input handled as a message */

    /* Program control */
    case 'A': /* Action */

    /* String building */
    case 'S': /* Return the string to the client */


    /* Input/output */
    case 'O': /* Output */
      sprintf( error_block.errmess, "Action %c not implemented", a->action );
      error_block.errnum = 0;
      error_display( &error_block );
      break;

    default:
      sprintf( error_block.errmess, "Action %c not known", a->action );
      error_block.errnum = 0;
      error_display( &error_block );
  }
  if( pending )
  { ap->action = *a;
    for( i = 0; i < MAX_ARG; i++ )
      ap->action.arg[i] = myStrdup( ap->action.arg[i]);
    ap = NULL;
    ap = myMalloc( sizeof( ActionPending ) );   
  }
  if( er ) /* this bit will need enhancing */
  { error_display( er );
  }
  return finished;
}

int action_events( int ec, ToolboxEvent *e, IdBlock *id, void *h )
{ Action *a, target = emptyAction;
  char buffer[BUFF_SIZE];
  _kernel_oserror* er = NULL;
  h = h; e = e;
  
  target.object = id->self_id;
  target.component = id->self_component;
  target.event = ec;
  target.value = buffer;
  er = read_gadget(target.object, target.component, target.value, BUFF_SIZE);
  if( er )
  { if(    er->errnum == ERROR_GADGET_NO_VALUE
        || er->errnum == ERROR_GADGET_NOT_UNDERSTOOD
        || er->errnum == ERROR_CLASS_NO_VALUE
        || er->errnum == ERROR_CLASS_NOT_UNDERSTOOD
      )
      read_toolbox( ec, e , -1, target.value, BUFF_SIZE);
  }  
  if( debug )
  { fputs( "\nReceived event\n", debug );
    debug_action( &target );
  }   
  a = find_action( firstAction, &target);
  while( a )
  { if( action( a, id, 0x200, (WimpPollBlock *) e ) ) break;
      /* implements the N action */
    a = find_action( a->next, &target);
  }
  return 0;
}

int action_messages( WimpMessage *message, void *handle )
{ Action *a, target = emptyAction;
  char buffer[BUFF_SIZE];
  _kernel_oserror* er = NULL;
  handle = handle;
  
  target.event = message->hdr.action_code;
  target.value = buffer;
  switch( message->hdr.action_code )
  { case 1: /* DataSave */
    case 3: /* DataLoad */
      NER( window_wimp_to_toolbox( 0,
                                   message->data.data_save.destination_window,
                                   message->data.data_save.destination_icon,
                                   &target.object, &target.component));
      break;

    default:
      target.object = -1;
      target.component = -1;
      break;
  }    

  er = read_message( message, 1, target.value, BUFF_SIZE, NULL, NULL, NULL);
  /* probably should be some error trapping here ***********/
  
  a = find_action( firstMessage, &target);
  while( a )
  { if( action( a, NULL, 17, (WimpPollBlock *) message ) ) break;
    a = find_action( a->next, &target);
  }
  return 0;
}

/* end of dBoxTools:action.c */
