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

#include "prtrans.h"

#if !defined(__MAIN_C__)
#define main	main_prload
#endif

int main (int argc, char **argv);

unsigned char buffer[65536];

#define RUN_RUN		1
#define RUN_JUMP	2
#define RUN_LOADBASIC	4
#define RUN_LOADADDR	8

int main (int argc, char **argv) {
  unsigned runflag = 0, jumpaddress = 0, basicaddr, driveraddr;
  FILE *file;
  unsigned bank = 0, start, given_start = 0;
  unsigned long length;
  char **parameters = argv;
  baseaddr = portaddr[DEFAULT_PORT];

  while (*++parameters && **parameters == '-') { /* check for options */
    if (parameters[0][1] == '-') { /* "--" ends options */
      parameters++;
      break;
    }

    switch (parameters[0][1]) {
    case 'a':
      given_start = strtoul (*++parameters, NULL, 16);
      if (given_start >= 65536)
	goto Usage;
      runflag = (runflag & ~(RUN_LOADBASIC)) | RUN_LOADADDR;

      break;

    case 'b':
      bank = strtoul (*++parameters, NULL, 16);

      if (bank > 255) {
        fprintf (stderr, "%s: Illegal memory bank specified.\n", *argv);
        return 1;
      }

      break;

    case 'p':
      baseaddr = strtoul (*++parameters, NULL, 16);

      if (baseaddr > 3) {
        fprintf (stderr, "%s: The printer port number must be between 0 and 3.\n",
                         *argv);
        return 1;
      }

      baseaddr = portaddr[baseaddr];

      break;

    case 'r':
      runflag = (runflag & ~(RUN_JUMP)) | RUN_RUN;
      break;

    case 'l':
      runflag = (runflag & ~(RUN_LOADADDR)) | RUN_LOADBASIC;
      break;

    case 'j':
      if (*++parameters) {
        runflag = (runflag & ~(RUN_RUN)) | RUN_JUMP;
        jumpaddress = strtoul (*parameters, NULL, 16);

	if (jumpaddress < 65536)
          break;
      }
      /* bleed through */

    case '?':
    case 'h':
    Usage:
      fprintf (stderr, "%s: Uploads files "
                       "to a memory area on a remote computer.\n\n", *argv);
      fprintf (stderr, "Usage: %s [options] filename(s)\n",
                       *argv);
      fprintf (stderr, "Options:\n\t"
			 "-a addr\t"		 
			     "Override the load address from the file\n\t"
                         "-b bank\t"
                             "Specify the memory bank (in hex)\n\t"
			 "-l\t"
			     "Load the file as BASIC.\n\t"
			 "-r\t"
			     "Performs the BASIC RUN command after the transfers.\n\t"
                         "-j addr\t"
			     "Jumps to the specified hex address after the transfers.\n\t"
                         "-p port\t"
                             "Specify the printer port (0 to 3)\n");
      return 1;

    default:
      fprintf (stderr, "%s: Illegal option `%s'.\n", *argv, *parameters);
      goto Usage;
    }
  }

  if (prinit ()) {
    fprintf (stderr, "%s: Could not get the I/O permissions.\n", *argv);
    return 4;
  }

  if (!*parameters) /* no file name specified */
    goto Usage;

  while (*parameters) {
    if (!(file = fopen(*parameters, "rb"))) {
      fprintf (stderr, "%s: Could not open the file `%s'.\n", *argv,
                       *parameters);
      return 5;
    }

    if (fseek (file, 0, SEEK_END)) {
      fprintf (stderr, "%s: Could not seek to the end of the file `%s'.\n",
                       *argv, *parameters);
      fclose (file);
      return 5;
    }

    length = ftell (file);

    if (length < 3) {
      fprintf (stderr, "%s: File `%s' is shorter than 1 byte.\n", *argv,
                       *parameters);
      fclose (file);
      return 5;
    }

    length -= 2;

    fseek (file, 0, SEEK_SET);

    if (length > 65536) {
      fprintf (stderr, "%s: File `%s' is longer than 64 kilobytes.\n",
                       *argv, *parameters);
      fclose (file);
      return 5;
    }

    start = fgetc (file);
    start |= (fgetc (file) << 8);

    if (length > fread (buffer, 1, length, file)) {
      fprintf (stderr, "%s: Reading the file `%s' failed.\n",
		       *argv, *parameters);
      fclose (file);
      return 5;
    }

    output (REQ_INFO); /* request machine type info */

    fprintf (stderr, "%s: Preparing to upload `%s' to machine type %u.\n",
                     *argv, *parameters, wait_input ());

    driveraddr = input();
    driveraddr |= input() << 8;
    basicaddr = input();
    basicaddr |= input() << 8;

    fprintf (stderr, "%s: Driver address %04X, BASIC start address %04X, "
                     "original load address %04X.\n",
                     *argv, driveraddr, basicaddr, start);

    if (runflag & RUN_LOADBASIC)
      start = basicaddr;
    if (runflag & RUN_LOADADDR)
      start = given_start;

    output (REQ_LOAD); /* op code for upload */

    output (bank); /* specify the bank address */

    if (input ()) {
      fprintf (stderr, "%s: not ready to transfer\n", *argv);
      fclose (file);
      return 6;
    }
    else
      fprintf (stderr, "%s: ok to transfer\n", *argv);

    output (start);
    output (start >> 8);
    output (start + length);
    output ((start + length) >> 8);

    send (buffer, length);

    fclose (file);
    parameters++;
  }

  if (runflag & 1)
    output (REQ_RUN); /* tell the server to shut off and to run the code */
  else if (runflag == 2) { /* jump to a program address */
    output (REQ_JUMP);
    output (0);       /* the bank address */
    output (jumpaddress);
    output (jumpaddress >> 8);
  }

  prclose ();

  return 0;
}
