/*
 * 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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "prtrans.h"

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

#if defined(__MAIN_C__)
unsigned char buffer[256];
#else
extern unsigned char buffer[];
#endif

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

int
main(int argc, char **argv)
{
  FILE *file = stdin;
  unsigned char device = 8;
  unsigned char secaddr = 1;
  unsigned char byte;
  char **parameters = argv;
  char *remotefile;
  char *localfile;
  char *portspecified = NULL;
  static char prgname[128];
  char *prg = prgname; /* loader program file name */
  int specified_remotefile = 0;
  baseaddr = portaddr[DEFAULT_PORT];

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

    switch (parameters[0][1]) {
    case 'd':
      device = strtoul (*++parameters, NULL, 0);

      if (device > 15) {
	fprintf (stderr, "%s: Illegal device number specified.\n", *argv);
	return 1;
      }

      break;

    case 'l':
      prg = *++parameters;
      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;
      }

      portspecified = *parameters;
      baseaddr = portaddr[baseaddr];
      break;

    case 's':
      secaddr = strtoul (*++parameters, NULL, 0);

      if (secaddr > 15) {
	fprintf (stderr, "%s: Illegal secondary address specified.\n", *argv);
	return 1;
      }

      break;

    case '?':
    case 'h':
    Usage:
      fprintf (stderr, "%s: Writes a local file to a file on a remote "
		       "computer.\n\n", *argv);
      fprintf (stderr, "Usage: %s [options] filename [remote filename]\n",
		       *argv);
      fprintf (stderr, "Options:\n\t"
			 "-d device\t"
			     "Specify the device number (0-15)\n\t"
			 "-l filename\t"
			     "Specify the filename of the client program\n\t"
			 "-p port\t"
			     "Specify the printer port (0 to 3)\n\t"
			 "-s sec. addr.\t"
			     "Specify the secondary addrsse (0-15)\n");
      fprintf (stderr, "The remote filename is converted to PETSCII.\n");

      return 1;

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

  if (!*parameters) goto Usage;

  localfile = *parameters++;
  remotefile = strdup(localfile);

  if (*parameters) {
    remotefile = *parameters++;
    specified_remotefile = 1;
  }
  ascii2petscii(remotefile);

  if (!specified_remotefile && localfile[1] == ':') {
    localfile += 2;	/* strip 0: or 1: from local filename */
  }
  if (strcmp(localfile, "-") == 0) {
    file = stdin;
  } else if (!(file = fopen(localfile, "rb"))) {
    fprintf (stderr, "%s: Could not open the file `%s'.\n", *argv,
		       localfile);
    return 1;
  }

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

  /* determine the program name to download */
  wait_output (REQ_INFO);
  sprintf (prgname, "PRLINK_PRWFILE%u", wait_input());
  getname (prgname, prgname, "prwfile.prg");
  input(); input(); input(); input(); /* skip the address information */

  {
    int addr;

    FILE *f = fopen(prg, "r");
    if (f == NULL) {
      fprintf (stderr, "%s: Cannot find %s to download\n", *argv, prg);
      prclose();
      return 1;
    }

    addr = fgetc(f);
    addr |= fgetc(f) << 8;
    fclose(f);

#if defined(__MAIN_C__)
    {
      char cmd[80];
      sprintf(cmd, "prload -j %x ", addr);

      if (portspecified) {
	strcat (cmd, "-p ");
	strcat (cmd, portspecified);
	strcat (cmd, " ");
      }

      strcat (cmd, prg);

      fprintf (stderr, "%s\n", cmd);
      system(cmd);
    }
#else
    {
      char saddr[10];

      sprintf (saddr, "%x", addr);

#define STR2(s)     # s
#define STR(s)	    STR2(s)

      vmain (main_prload, 6,
	     "prload",
	     "-j", saddr,
	     "-p", (portspecified ? portspecified : STR(DEFAULT_PORT)),
	     prg,
	     NULL );
    }
#endif
  }

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

  byte = strlen(remotefile);
  output(byte);
  send(remotefile, byte);
  output(device);
  output(secaddr);

  if ((byte = wait_input ()) != 0) {
    fprintf (stderr, "%s: file error %d\n", *argv, byte);
    output(255); /* terminate remote side */
    prclose();
    return 1;
  }
  fprintf(stderr, "Writing \"%s\" to \"%s\",%d,%d...\n",
          localfile, remotefile, device, secaddr);

  /* loop to send all file blocks */
  for (;;) {
    int length;
    int chksum;
    int i;

    length = fread(buffer + 1, 1, 255, file);

    chksum = 0;
    for (i = 0; i < length; i++) {
      chksum += buffer[1 + i];
    }
    buffer[0] = chksum;

    for (;;) {
      output((unsigned char)length);

      if (length == 0)
	break;	      /* end of file */

      send(buffer, length + 1);

      i = wait_input();

      switch (i) {
      case 0x80:
	goto nextblock;
      case 0x81:
	fprintf(stderr, "checksum error, resending...\n");
	break;
      default:
	fprintf(stderr, "Aborting\n");
	goto abort;
      }
    }
  nextblock:
    if (length == 0)
      break;
  }
abort:

  if (file != stdin) fclose(file);

  output(255);	/* terminate remote side */

  prclose ();

  return 0;
}

