#include "vrpn_Generic_server_object.h"

const int LINESIZE = 512;

#define CHECK(s) \
    retval = (s)(pch, line, config_file); \
    if (retval && d_bail_on_open_error) {\
      d_doing_okay = false; return; \
    } else {\
      continue; \
    }

#define next() pch += strlen(pch) + 1

void vrpn_Generic_Server_Object::closeDevices (void) {
  int i;
  for (i=0;i < num_buttons; i++) {
    if (verbose) fprintf(stderr, "\nClosing button %d ...", i);
    delete buttons[i];
  }
  for (i=0;i < num_trackers; i++) {
    if (verbose) fprintf(stderr, "\nClosing tracker %d ...", i);
    delete trackers[i];
  }
  for (i=0;i < num_analogs; i++) {
    if (verbose) fprintf(stderr, "\nClosing analog %d ...", i);
    delete analogs[i];
  }

  if (verbose) { fprintf(stderr, "\nAll devices closed...\n"); }
}


// --------------------------------------------------------------------------------------------------------------------------------------------------------------
/// Setup iOS Gun
// --------------------------------------------------------------------------------------------------------------------------------------------------------------

int vrpn_Generic_Server_Object::setup_iOSDevice (char * & pch, char * line, FILE * config_file) 
{
  char name[LINESIZE];
  char port[LINESIZE];

  // Get the arguments
  next();

  if (sscanf(pch, "%511s%511s", name, port) != 2) 
  {
	  fprintf(stderr, "Bad vrpn_iOS device line: %s\n", line);
	  return -1;
  }

  // Make sure there's room for a new analog
  if (num_analogs >= VRPN_GSO_MAX_ANALOG) 
  {
	  fprintf(stderr,"Too many Analogs in config file");
	  return -1;
  }

  if ( (analogs[num_analogs] = new vrpn_iOSDevice(name, port, connection)) == NULL )
  {
	  fprintf(stderr, "Can't create new vrpn_iOSDevice\n");
	  return -1;
  }
  else 
  {
	  num_analogs++;
  }

  return 0;
}

vrpn_Generic_Server_Object::vrpn_Generic_Server_Object(vrpn_Connection *connection_to_use, const char *config_file_name, int port, bool be_verbose, bool bail_on_open_error) :
  connection(connection_to_use),
  d_doing_okay(true),
  verbose(be_verbose),
  d_bail_on_open_error(bail_on_open_error),
  num_trackers(0),
  num_buttons(0),
  num_analogs(0)
  {
    FILE    * config_file;

    // Open the configuration file
    if (verbose) printf("Reading from config file %s\n", config_file_name);
    if ( (config_file = fopen(config_file_name, "r")) == NULL) {
        perror("vrpn_Generic_Server_Object::vrpn_Generic_Server_Object(): Cannot open config file");
        fprintf(stderr,"  (filename %s)\n", config_file_name);
        d_doing_okay = false;
            return;
    }

    // Read the configuration file, creating a device for each entry.
    // Each entry is on one line, which starts with the name of the
    //   class of the object that is to be created.
    // If we fail to open a certain device, print a message and decide
    //  whether we should bail.
    {
        char    line[LINESIZE]; // Line read from the input file
        char *pch;
        char    scrap[LINESIZE];
        char    s1[LINESIZE];
        int retval;

        // Read lines from the file until we run out
        while ( fgets(line, LINESIZE, config_file) != NULL ) {

          // Make sure the line wasn't too long
          if (strlen(line) >= LINESIZE-1) {
              fprintf(stderr,"vrpn_Generic_Server_Object::vrpn_Generic_Server_Object(): Line too long in config file: %s\n",line);
              if (d_bail_on_open_error) { d_doing_okay = false; return; }
              else { continue; }  // Skip this line
          }

          // Ignore comments and empty lines.  Skip white space before comment mark (#).
          if (strlen(line)<3) {
              continue;
          }
          bool ignore = false;
          for (int j=0; line[j] != '\0'; j++) {
              if (line[j]==' ' || line[j]=='\t') {
                  continue;
              }
              if (line[j]=='#') {
                  ignore = true;
              }
              break;
          }
          if (ignore) {
              continue;
          }

          // copy for strtok work
          strncpy(scrap, line, LINESIZE);
          // Figure out the device from the name and handle appropriately

          // WARNING: SUBSTRINGS WILL MATCH THE EARLIER STRING, SO
          // ADD AN EMPTY SPACE TO THE END OF STATIC STRINGS!!!!

          //    #define isit(s) !strncmp(line,s,strlen(s))
          #define isit(s) !strcmp(pch=strtok(scrap," \t"),s)

          // Rewritten to move all this code out-of-line by Tom Hudson
          // August 99.  We could even make it table-driven now.
          // It seems that we're never going to document this program
          // and that it will always be necessary to read the code to
          // figure out how to write a config file.  This code rearrangement
          // should make it easier to figure out what the possible tokens
          // are in a config file by listing them close together here
          // instead of hiding them in the middle of functions.

		  if (isit("vrpn_iOSDevice")) {
				  CHECK(setup_iOSDevice);
		  }

		  else {	// Never heard of it
			sscanf(line,"%511s",s1);	// Find out the class name
			fprintf(stderr,"vrpn_server: Unknown Device: %s\n",s1);
			if (d_bail_on_open_error) { d_doing_okay = false; return; }
			else { continue; }	// Skip this line
		  }
		}
      }

    // Close the configuration file
    fclose(config_file);
  }

vrpn_Generic_Server_Object::~vrpn_Generic_Server_Object()
{
  closeDevices();
}

void  vrpn_Generic_Server_Object::mainloop( void )
{
  int	i;

  // Let all the buttons generate reports
  for (i = 0; i < num_buttons; i++) {
	  buttons[i]->mainloop();
  }

  // Let all the trackers generate reports
  //for (i = 0; i < num_trackers; i++) {
	  //trackers[i]->mainloop();
  //}
  // Let all the analogs do their thing
  for (i=0; i< num_analogs; i++) {
	  analogs[i]->mainloop();
  }
}