/*
 * Copyright © 1994-1996 Marko Mäkelä and Olaf Seibert
 * Original Linux and Commodore 64/128/Vic-20 version by Marko Mäkelä
 * Ported to the PET and the Amiga series by Olaf Seibert
 * 
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with this program; if not, write to the Free Software
 *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

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

#include "prtrans.h"

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

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

/*
 * The largest scratch buffer in the program is 64K. If the modules
 * are unified, the other modules don't have to define their own scratch
 * buffers.
 */
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 char bank = 0;
  unsigned start, given_start = 0;
  unsigned 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);
      prclose ();
      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);
      prclose ();
      return 5;
    }

    length = ftell (file);

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

    wait_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);
      prclose ();
      return 6;
    }
    else
      fprintf (stderr, "%s: ok to transfer\n", *argv);

    output ((unsigned char)start);
    output ((unsigned char)(start >> 8));
    output ((unsigned char)(start + length));
    output ((unsigned char)((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 ((unsigned char)jumpaddress);
    output ((unsigned char)(jumpaddress >> 8));
  }

  prclose ();

  return 0;
}
