#include <hpcxx_rts.h>
#include <iostream.h>
#include <stdio.h>
#include "ToyClass.h"
#include "allHPCxxTemplates.h"

// tjs - 98.12.15
//
// This set of classes and associated global variables and global functions
// is to illustrate the object-oriented use of HPC++ global pointers to
// classes.
//
// In the parent Toy class, member data and functions used by the derived
// ToyServer and ToyClient classes.  If member functions are to be identical
// wholely used in the derived classes, then they are defined.  Otherwise
// they are declared as virtual and defined merely as stubs.
//
// The functions and variables of global scope are required to create and
// use HPC++ global pointers.  They are included in this file because they
// are invoked and accessed by member functions of the classes in this file.
// The global pointers could have been set up by the program(s) that use
// these classes, but in order to keep things as encapsulated as possible, I
// have moved that setup into the classes themselves.
//
// The implementation of HPC++ requires that any function that is remotely
// invoked must return a value.  As a result, some member functions in these
// classes return dummy variables.
//
// Because of templates of type Toy, certain member function calls depend on
// the Toy class being defined before they can be called from an object.
// Though common to all derived classes, these member functions are invoked
// from the derived classes instead of the parent class.

// Functions in the parent Toy class

void Toy::regFuncs() {
  regVal = 100;
  PrintID = hpcxx_register(Toy::printArr,regVal); regVal++;
  ExchangeID = hpcxx_register(Toy::exchangeArr,regVal); regVal++;
}

Toy::Toy() {
  regFuncs();
}

void Toy::printLocal() {
  cout << "  in Toy::printArr" << endl << flush;
  printf("    intArr:  ");
  for(int i=0;i<ARR_SIZE;i++)
    printf("%4d",intArr[i]);
  printf("\n"); fflush(stdout);
  
  printf("    negArr:  ");
  for(i=0;i<ARR_SIZE;i++)
    printf("%4d",negArr[i]);
  printf("\n"); fflush(stdout);
}

void Toy::readArr(int size) {
  ToyGP_Ptr->read(this,size);
}

// Functions in the derived ToyServer Class

ToyServer :: ToyServer() : Toy() {

  hpcxx_registerClass((Toy *)NULL);             // must go in derived class
  ToyGP_Ptr = new HPCxx_GlobalPtr<Toy>(this);
  gToyGP = *ToyGP_Ptr;
  getToyGPID = hpcxx_register(getToyGP,regVal); regVal++;

  for(int i=0;i<ARR_SIZE;i++) {
    intArr[i] = i;
    negArr[i] = -i;
  }
}

int ToyServer::printArr(void) {
  cout << "  in ToyServer::printArr" << endl << flush;
  printLocal();
  return(0);
}

int ToyServer::exchangeArr() {
  int
    tmpInt;
  for(int i=0;i<ARR_SIZE;i++) {
    tmpInt = intArr[i];
    intArr[i] = negArr[i];
    negArr[i] = tmpInt;
  }
  return(0);
}

// Functions in the derived ToyClient class

ToyClient::ToyClient(HPCxx_ContextID *serverContextID) : Toy() {

  // set up for a global pointer to this object
  hpcxx_registerClass((Toy *)NULL);             // must go in derived class
  ToyGP_Ptr = new HPCxx_GlobalPtr<Toy>(this);
  getToyGPID = hpcxx_register(getToyGP,regVal); regVal++;
  hpcxx_invoke(*serverContextID, *ToyGP_Ptr, getToyGPID);  
}

int ToyClient::printArr(void) {
  int
    rtrnVal;
  hpcxx_minvoke(ToyGP_Ptr, rtrnVal, PrintID);  
  return(rtrnVal);
}

int ToyClient::exchangeArr() {
  int
    rtrnVal;
  hpcxx_minvoke(ToyGP_Ptr, rtrnVal, ExchangeID);
  return(rtrnVal);
}



// Global Functions

HPCxx_GlobalPtr<Toy> getToyGP(void)     // get GP to Toy class
{
  return(gToyGP);
}

// HPC++ pack & unpack functions.  These are friends to Toy class.

void hpcxx_pack(HPCxx_Buffer b, Toy *ToyObj, int size){
  if(size >0) {
    b.pack(ToyObj->intArr, ARR_SIZE);
  } else {
    b.pack(ToyObj->negArr, ARR_SIZE);
  }      
}

void hpcxx_unpack(HPCxx_Buffer b, Toy *ToyObj, int size){
  if(size >0) {
    b.unpack(ToyObj->intArr, ARR_SIZE);
  } else {
    b.unpack(ToyObj->negArr, ARR_SIZE);
  }      
}


