/*
	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 3 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, see <http://www.gnu.org/licenses/>.

	Jakub Ladman 2010
*/



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

#ifndef GCC				/* to enable debugging on gcc based system */
#include <sys.h>
#else
#define outp(a,b)		printf("outp port %#x data %#x\n", (a), (b));
#define inp(a)			0
#endif

#define UC_CMD_PORT	0x50
#define UC_DATA_PORT	0x51

#define UC_REPO_RESET	0x0
#define UC_ASCII	0x1
#define UC_SHASCII	0x2	/* will be not used */

#define uc_binary_cmd(a)	outp(UC_CMD_PORT, (a))

#define MAXFNLEN	40

#define D_TYPE_TXT	0
#define D_TYPE_BIN	1

#ifdef GCC
FILE *input_file;
#endif

typedef struct {
	char fname[MAXFNLEN];
	unsigned long flen;
	char attr;
} fl_member;

/* string.h functions not found in the hitech-c library, this two functions came from SDCC project */

char * c_strstr(char * str1, char * str2) {
	char * cp = str1;
	char * s1;
	char * s2;

	if (!*str2)
		return str1;

	while (*cp) {
		s1 = cp;
		s2 = str2;

		while (*s1 && *s2 && !(*s1 - *s2))
			s1++, s2++;

		if (!*s2)
			return (cp);

		cp++;
	}

	return (NULL);
}

char * c_strtok(char * str, char * control) {
	static char * s;
	register char * s1;

	if (str)
		s = str;
	if (!s)
		return NULL;

	while (*s) {
		if (strchr(control, *s))
			s++;
		else
			break;
	}

	s1 = s;

	while (*s) {
		if (strchr(control, *s)) {
			*s++ = '\0';
			return s1;
		}
		s++;
	}

	s = NULL;

	if (*s1)
		return s1;
	else
		return NULL;
}


void uc_send_cmd(char *cmd) {
	if (cmd == NULL)
		return;
	while (*cmd != 0) {
		outp(UC_CMD_PORT, *(cmd++));
	}
}

int uc_get_data(char *buffer, unsigned int len, char binary) /* nacte data z unikarty */
{ /* binarni prenos konci po nacteni len bytu */
	/* textovy se ukonci prijetim 0x00 */
	int i;
	if ((buffer == NULL) || (len <= 0))
		return -1; /* neplatny buffer nebo limit poctu bytu */

	for (i = 0; i < len; i++) {

		buffer[i] = inp(UC_DATA_PORT);

#ifdef GCC
		fread(&(buffer[i]), 1, 1, input_file);

#endif

		/*	printf("%d = %02x \n", i, buffer[i]);*/

		if (!binary) /* pri txt prenosu */
		{
			buffer[i] &= 0x7f; /* vynulovat osmy bit */
			if (buffer[i] == 0)
				break;
			if ((buffer[i] <= 'z') && (buffer[i] >= 'a'))
				buffer[i] = buffer[i] - ('a' - 'A');

		}

	}

	return i;
}

int uc_get_directory(fl_member *filelist, char *path) /* vrati vyplnene pole struktur se seznamem souboru */
{
#define CMDLEN		(MAXFNLEN + 20)
#define DATALEN		4096
	char command[CMDLEN];
	char *buffer = NULL, *str, *token;

	int i, j;

	if ((filelist == NULL) || (path == NULL))
		return -1; /* neplatne parametry */
	buffer = malloc(DATALEN);
	if (buffer == NULL)
		return -2; /* nepridelena pamet pro buffer */

	sprintf(command, "OPEN FILEPATH %s/\r", path);

	printf("Sending command: %s\n", command);

	uc_send_cmd(command);

	if (uc_get_data(buffer, DATALEN, D_TYPE_TXT) < 0) {
		puts("error getting data");
		free(buffer);
		return -3;
	}

	for (j = 1, i = 0, str = buffer;; j++, str = NULL) {
		token = c_strtok(str, "\r");
		if (token == NULL)
			break;

		/*	printf("%d: %s\n", j, token);*/

		if (j % 2) {
			strncpy(filelist[i].fname, token, MAXFNLEN);
		} else {
			filelist[i++].flen = atol(token);
		}
	}
	free(buffer);
	return i; /* vraci pocet polozek adresare */
}

void uc_get_file(char *path, char *file, unsigned int len) {

	FILE *out_file;
	char filename[13];
	char *s;
	char found = 0;
	char *databuf;
	unsigned int i, j;

	i = strlen(file);

	if (i > 12) {

		printf("filename \"%s\" too long - shortening\n", file);
		strncpy(filename, &(file[i - 12]), 12);

	} else
		strncpy(filename, file, 12);
	filename[12] = 0;

	i = strlen(filename);
	s = filename;
	while (*s != 0) {

		if (*s == '.') {
			if (strlen(s) == 3)
				found = 1;
			else
				*s = '_'; /* tecka jinde nez na ctvrty pozici od konce je nahrazena podtrzitkem */
		}
		s++;
	}
	if (!found) /* tecka neni na treti pozici od konce */
		filename[i - 4] = '.';

#define DATABLOCK	1024

	databuf = NULL;
	j = (len / DATABLOCK) * DATABLOCK;
	if (len % DATABLOCK)
		j += DATABLOCK;

	while (databuf == NULL) {
		databuf = malloc(j);
		if (databuf == NULL)
			j -= DATABLOCK;
		if (j == 0)
			break;
	}

	if (databuf != NULL) {
		printf("allocated %u bytes\n", j);

		printf("opening file %s for writing\n", filename);

		out_file = fopen(filename, "wb");
		if (out_file != NULL) {

			sprintf(databuf, "OPEN FILEPATH %s/%s\r", path, file);

			printf("Sending command: %s\n", databuf);

			uc_send_cmd(databuf);

			while (len > j) {
				uc_get_data(databuf, j, D_TYPE_BIN);
				fwrite(databuf, 1, j, out_file);
				len -= j;
			}

			if (len > 0) {
				uc_get_data(databuf, len, D_TYPE_BIN);
				fwrite(databuf, 1, len, out_file);
			}

			fclose(out_file);
		}

		free(databuf);
		databuf = NULL;
	}

}

int dir_and_file(char *path, char **file) /* ze vstupniho retezce v path */
/* oddeli jmeno souboru a vrati ve file */
{
	int i = 0;
	char *ptr = path;
	while (*ptr != 0) { /* najdeme konec retezce */
		/*	printf("searching end of string %d %02x \'%c'\n",i, *ptr, *ptr); */
		ptr++;
		i++;

	}

	/* ptr ted ukazuje na ukoncovaci znak retezce */

	/*    printf("path=%#x\t ptr=%#x\t i=%d\n", path, ptr, i);    */

	while (*(ptr) != '/') { /* najdeme posledni lomitko v retezci */
		/*	printf("searching / from end %d %02x \'%c'\n",i, *ptr, *ptr); */
		ptr--;
		i--;
		if (i < 0) {
			*file = NULL;
			return i; /* nenalezeno */
		}
	}
	/* ptr ted ukazuje na posledni znak '/' */
	/*    printf("path=%#x\t ptr=%#x\t i=%d\n", path, ptr, i);*/
	*ptr = 0; /* nahradime lomitko koncem retezce */
	*file = ptr + 1; /* nasledujici znak je zacatek filename */

	return i;
}

int main(int argc, char *argv[]) {

	int i, j;
	char *path, *file;
	static char def_path[5] = "/";
	char buffer[50];
	char c;
	fl_member filelist[100];

	file = NULL;

#ifdef GCC
	puts("Compiled for debugging under GCC");
	input_file = fopen("unicard_input.bin", "rb");
	if (input_file == NULL) {
		puts("Can't open data file!");
		return -1;
	}
#endif

	uc_binary_cmd(UC_REPO_RESET);
	uc_binary_cmd(UC_ASCII);

	/*
	 for (i = 0; i < argc; i++) {
	 printf("argument %d ...\"%s\"\n", i, argv[i]);
	 }
	 */

	if (argc > 1)
		path = argv[1];
	else
		path = def_path;

	/*	if (*/
	dir_and_file(path, &file) /*< 0) {
	 puts("cmdline parsing error");
	 return -1*/;
	/*	}*/

	printf("Path: %s filename: %s\n", path, file);

	j = uc_get_directory(filelist, path);
	printf("Files in directory %d\n", j);

#ifdef GCC
	rewind(input_file);
#endif

	for (i = 0; i < j; i++) {
		printf("%d\t%s  %07lu\n", i, filelist[i].fname, filelist[i].flen);

		if (file != NULL)
			if (!strncmp(filelist[i].fname, file, MAXFNLEN)) {
				puts("Command line referred filename found.");
				if (c_strstr(filelist[i].fname, ".DSK")) {

					printf("Found disk image\n");
					printf("Would you like to remount it to a diskdrive? (No/A/B/C/D)\n");
					scanf("%c", &c);

					if ((c >= 'a') && (c <= 'd'))
						c = c - 'a';
					else if ((c >= 'A') && (c <= 'D'))
						c = c - 'A';
					else
						continue;

					sprintf(buffer, "SETUP SET FD%u %s/%s\r", c, path, file);
					printf("Sending command: %s\n", buffer);
					uc_send_cmd(buffer);
#ifndef GCC
					bdos(13); /* reset diskoveho systemu pro nacteni nove diskety */
#endif
				} else
					uc_get_file(path, file, filelist[i].flen);
			}

	}

#ifdef GCC
	fclose(input_file);
#endif
	puts("end");
	return 0;
}

