/*

	MyMouse : BridgeBoard's MouseServ demo program

	(C) 1995 Remi Lenoir

*/

#include	<stdio.h>
#include	<conio.h>
#include	<dos.h>
#include	<malloc.h>
#include	"types.h"
#include	"mymouse.h"

// Segment information
UWORD ParamSeg, ParamOff, BuffSeg, Flags;

// Prototypes
void CopyMouseServStruct( struct MouseServ *, struct MouseServ * );
void PrintMouseServStruct( struct MouseServ * );
UBYTE GetBase( UBYTE Service, UWORD *ParmSeg, UWORD *ParmOff, UWORD *BuffSeg );
UBYTE GetService( ULONG ApplicationID, UWORD LocalID, UWORD Flags, int (*Handler)() , struct ServiceData **SData );
UBYTE ReleaseService( struct ServiceData *SData );
UBYTE LockServiceData( struct ServiceData *SData );
UBYTE UnlockServiceData( struct ServiceData *SData );

void main( void )
{
  UBYTE error;
  struct ServiceData *SData;
  struct MouseServ *mss, copy_of_mss;
  RPTR offset;
  UWORD Copy_Of_UpdateCounter;

  // Get Janus Base address and memories segment addresses
  error = GetBase( 16, &ParamSeg, &ParamOff, &BuffSeg );

  if ( error != 0 )
  {
    printf("GetBase() error = %d\n", error);
    exit( 5 );
  }

  // Ask the Amiga to load the service and wait for its availability
  Flags = GETS_ALOAD_A | GETS_WAIT ;

  error = GetService( AMOUSESERV_APPLICATION_ID, AMOUSESERV_LOCAL_ID, Flags, 0L, &SData );
  if ( error != 0 )
  {
    printf("GetService() error = %d\n", error);
    exit( 5 );
  }

  LockServiceData( SData );
  UnlockServiceData( SData );

  // Get the pointer on the application parameter memory
  mss = (struct MouseServ *) SData->sd_PCMemPtr;

  clrscr();	// Clear screen

  printf("MouseServ client demo. (C) Remi Lenoir");  // Lame advertisement
  gotoxy( 1, 13);			// position cursor (col,line)
  printf("Press Q or X to exit");

  // Fields can be written by the client
  mss->MouseX = 0;
  mss->MouseY = 0;
  mss->LeftButtonDownCounter = 0;
  mss->RightButtonDownCounter = 0;
  mss->LeftButtonUpCounter = 0;
  mss->RightButtonUpCounter = 0;
  mss->ActualButtonsState = 0;

  Copy_Of_UpdateCounter = 0;

  do
  {
    delay( 10 );
    if( Copy_Of_UpdateCounter != mss->UpdateCounter )
    {
      do
      {
	Copy_Of_UpdateCounter = mss->UpdateCounter ; // Save UpdateCounter
	CopyMouseServStruct( mss, &copy_of_mss );    // Copy MouseServ structure
      }while( Copy_Of_UpdateCounter != mss->UpdateCounter );
      gotoxy( 1, 3 );
      PrintMouseServStruct( &copy_of_mss );
    }

    // Check if service no longer exists
    if( SData->sd_Flags & 0x0001 )
    {
      printf("Service no longer exists\n");
      break;
    }

    // Check if user wants to exit
    if ( kbhit() )	// check if a key was pressed
    {
    int car;

      car = toupper( getch() );
      if ( car == 'Q' || car == 'X' )
	break;
    }

  }while ( TRUE );

  printf("\n\n\nExiting...\n");
  error = ReleaseService( SData );
  exit( 0 );
}


// Copy the MouseStructure

void CopyMouseServStruct( struct MouseServ *src, struct MouseServ *dest )
{
int i;

  for( i = 0; i < sizeof( struct MouseServ ); i++ )
    ((UBYTE *)dest)[i] = ((UBYTE *)src)[i];
}


// Print the MouseStructure fields

void PrintMouseServStruct( struct MouseServ *mss )
{
  printf( "MouseX         = %04x\n", mss->MouseX );
  printf( "MouseY         = %04x\n", mss->MouseY );
  printf( "LeftButtonDwn  = %04x\n", mss->LeftButtonDownCounter );
  printf( "RightButtonDwn = %04x\n", mss->RightButtonDownCounter );
  printf( "LeftButtonUp   = %04x\n", mss->LeftButtonUpCounter );
  printf( "RightButtonUp  = %04x\n", mss->RightButtonUpCounter );
  printf( "ActualButtons  = %04x\n", mss->ActualButtonsState );
  printf( "Unknown        = %02x\n", mss->Unknown );
  printf( "UpdateCounter  = %02x\n", mss->UpdateCounter );
}


// Get the segments and offsets of the shared memory areas

UBYTE GetBase( UBYTE Service, UWORD *ParmSeg, UWORD *ParmOff, UWORD *BuffSeg )
{
  UBYTE status;
  struct REGPACK regs;

  /*
     AH   : Function number
     AL   : Janus Service Number
  */
  regs.r_ax = ( 1 << 8 ) | Service;

  intr( INT_JANUS, &regs );

  *ParmSeg = (UWORD) regs.r_es;
  *ParmOff = (UWORD) regs.r_di;
  *BuffSeg = (UWORD) regs.r_dx;
  status = (UBYTE) (regs.r_ax & 0x00ff);
  return ( status );
}


// Ask Janus to be a client of a service

UBYTE GetService( ULONG ApplicationID, UWORD LocalID, UWORD Flags, int far (*Handler)() , struct ServiceData **SData )
{
  UBYTE status;

  struct REGPACK regs;

  /*
     AH     : Function number
     AL     : Flags
     DS:SI  : Application ID
     CX     : Local ID
     ES:DI  : Handler
  */
  regs.r_ax = ( 11 << 8 ) | Flags;
  regs.r_ds = (UWORD) ( ApplicationID >> 16 );
  regs.r_si = (UWORD) ( ApplicationID & 0x0000ffff);
  regs.r_cx = LocalID;
  regs.r_es = FP_SEG( (void far *) Handler );
  regs.r_di = FP_OFF( (void far *) Handler );

  intr( INT_JANUS, &regs );

  *SData = (struct ServiceData *) MK_FP( regs.r_es, regs.r_di );
  status = (UBYTE) (regs.r_ax & 0x00ff);
  return( status );
}


// Lock the ServiceData structure

UBYTE LockServiceData( struct ServiceData *SData )
{
  UBYTE status;
  struct REGPACK regs;

  /*
     AH     : Function number
     ES:DI  : Pointer to SData
  */
  regs.r_ax = ( 15 << 8 );
  regs.r_es = FP_SEG( (void far *) SData );
  regs.r_di = FP_OFF( (void far *) SData );

  intr( INT_JANUS, &regs );

  status = (UBYTE) (regs.r_ax & 0x00ff);
  return( status );
}


// UnLock the ServiceData structure

UBYTE UnlockServiceData(struct ServiceData *SData )
{
  UBYTE status;
  struct REGPACK regs;

  /*
     AH     : Function number
     ES:DI  : Pointer to SData
  */
  regs.r_ax = ( 16 << 8 );
  regs.r_es = FP_SEG( (void far *) SData );
  regs.r_di = FP_OFF( (void far *) SData );

  intr( INT_JANUS, &regs );

  status = (UBYTE) (regs.r_ax & 0x00ff);
  return( status );
}


// Tells Janus we stop using the service

UBYTE ReleaseService( struct ServiceData *SData )
{
  UBYTE status;
  struct REGPACK regs;

  /*
     AH     : Function number
     ES:DI  : Pointer to SData
  */
  regs.r_ax = ( 13 << 8 );
  regs.r_es = FP_SEG( (void far *) SData );
  regs.r_di = FP_OFF( (void far *) SData );

  intr( INT_JANUS, &regs );

  status = (UBYTE) (regs.r_ax & 0x00ff);
  return ( status );
}

