/*
 * 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_prcart
#endif

unsigned char auxcode[] = {
  0x78, 0xa9, 0x41, 0x8d, 0x04, 0xa0, 
  0xa2, 0xff, 0x9a, 0xd8, 0xe8, 0x4c, 0, 0,
  0xa2, 0x0d, 0x8d, 0x04, 0xa0, 0x20, 0x8d, 0xfd,
  0x20, 0x52, 0xfd, 0x20, 0xf9, 0xfd,
  0x20, 0, 0, 0x4c, 0x38, 0xfd
};

unsigned char *auxstart = &auxcode[12];
unsigned char *srvstart = &auxcode[29];

#define AUXJUMP (auxaddr + 14)

#if defined(__MAIN_C__)
unsigned char buffer[8192]; /* input buffer */
#else
extern unsigned char buffer[];
#endif

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

int main (int argc, char **argv) {
  unsigned auxaddr = 20000, driveraddr, basicaddr;
  FILE *file = stdin;
  unsigned start = 0xa000, jumpaddress = 0,
           flag = 0, length;
  unsigned i;
  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 '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 'a':
      if (*++parameters)
        if (65536 > (auxaddr = strtoul (*parameters, NULL, 10)))
          break;

      goto Usage;

    case 'j':
      if (*++parameters) {
	flag = 1;

        jumpaddress = strtoul (*parameters, NULL, 16);

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

    case '?':
    case 'h':
    Usage:
      fprintf (stderr, "%s: Uploads a cartridge to the VIC-20.\n\n", *argv);
      fprintf (stderr, "Usage: %s [options] [filename.a000 [filename.6000]]\n",
                       *argv);
      fprintf (stderr, "Options:\n\t"
                         "-j addr\t"
			     "Jumps to the specified address after the transfers.\n\t\t"
                             "Not useful with auto-start cartridges.\n\t"
			 "-a addr\t"
			     "Specifies the restart address of the game.  Default=20000.\n\t\t"
			     "Only useful with auto-start cartridges.\n\t"
                         "-p port\t"
                             "Specify the printer port number (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;
  }

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

  if (20 != wait_input ()) {
    fprintf (stderr, "%s: The client is not a VIC-20.\n", *argv);
    input (); input (); input (); input (); /* read the rest of the info */
    return 5;
  }

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

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

  if (*parameters) file = NULL;

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

    length = fread (buffer, 1, 8192, file);

    if (length != 8192 && length != 4096) {
      fprintf (stderr, "%s: Short file.\n", *argv);

      fclose (file);

      return 5;
    }

    if (start == 0xa000 && !flag &&
        !memcmp (&buffer[4], "A0\xC3\xC2\xCD", 5)) {
      /* a0CBM autostart code found and no other jumpaddress specified */
      flag = 2;

      auxstart[0] = buffer[0];
      auxstart[1] = buffer[1];
      buffer[0] = (unsigned char)AUXJUMP;
      buffer[1] = AUXJUMP >> 8;
    }

    output (REQ_LOAD); /* op code for upload */
    output (0); /* specify the bank address */

    if (input ()) {
    notReady:
      fprintf (stderr, "%s: not ready to transfer\n", *argv);
      fclose (file);
      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);

    if (file == stdin) {
      i = getc (file);

      if (feof (file))
        break;

      ungetc (i, file);
    }
    else {
      fclose (file);
      parameters++;
    }

    if (start == 0xa000)
      start = 0x6000;
    else
      break;
  }

  if (flag) { /* start the cartridge */
    if (flag == 2) {
      output (REQ_LOAD); /* first send the startup code */
      output (0);

      if (input ())
        goto notReady;

      fprintf (stderr, "%s: ok to transfer\n", *argv);

      output ((unsigned char)auxaddr);
      output ((unsigned char)(auxaddr >> 8));
      output ((unsigned char)(auxaddr + sizeof auxcode));
      output ((unsigned char)((auxaddr + sizeof auxcode) >> 8));

      srvstart[0] = (unsigned char)driveraddr;
      srvstart[1] = driveraddr >> 8;

      for (i = 0; i < sizeof auxcode; i++)
        output (auxcode[i]);

      jumpaddress = auxaddr;

      fprintf (stderr, "%s: Type SYS%u to restart the game after reset.\n",
                       *argv, auxaddr);
    }

    output (REQ_JUMP);
    output (0);
    output ((unsigned char)jumpaddress);
    output ((unsigned char)(jumpaddress >> 8));
  }

  prclose ();

  return 0;
}
