#include <stdio.h>

#include "windows.h"
#include "pc3comm.h"
#include "scio.h"

// NI
#define CommandClass 0x01
#define MaxStrLen 100
int ni_send(LPSTR str, int len);
int ni_recv();
int ni_select(char r0, char r1);
int ni_readbinary(int len);

int port = 1;
int aflag, vflag;

char *monthtab[] = {
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
    "???",
    NULL
};

main(ac, av)
int ac;
char *av[];
{
    char cmd[64], buf[100];
    int i, n, rtn = 1;
    unsigned short len, r1, r2;
	
	// NI
	char ni_str[4];
	ni_str[0] = 0x01;
	ni_str[1] = 0x02;
	ni_str[2] = 0x03;
	ni_str[3] = 0x04;

    while (ac > 1 && av[1][0] == '-') {
	switch (av[1][1]) {
	case '1':
	case '2':
	    port = av[1][1] - '1';
	    break;
	case 'a':
	    aflag = 1;
	    break;
	case 'v':
	    vflag = 1;
	    break;
	}
	ac--;
	av++;
    }

    /* open reader */
    stuff_cmd(COMM, cmd);
    cmd[2] = port;
    len = 0;
    SCBios(cmd, buf, &len, &r1, &r2);
    if (r2) {
	printf("can't open reader\n");
	goto futz;
    }

    /* reset */
    stuff_cmd(RESET, cmd);
    len = cmd[4];
    SCBios(cmd, buf, &len, &r1, &r2);
    if (r2) {
	printf("Slag!\n");
	goto futz;
    }

	// NI original ...
    // open 3f.00 (serial number?) 
			
	if (ni_select(0x3f, 0x00) < 0) {
		printf("cannot select 3f.00\n");
		goto futz;
	}
	printf("selected 3f.00\n");

	if (ni_select(0x77, 0x77) < 0) {
		printf("cannot select 77.77\n");
		goto futz;
	}
	printf("selected 77.77\n");

	if (ni_select(0x77, 0x01) < 0) {
		printf("cannot select 77.01\n");
		goto futz;
	}
	printf("selected 77.01\n");
	
	if (ni_writebinary(ni_str, 4) < 0) {
		printf("cannot write\n");
		goto futz;
	}
	printf("wrote\n");
	
	ni_readbinary(4);

	/*
	if (open_file(cmd, 0x3f, 0x00) < 0)
		printf("can't open 3f.00\n");
	else printf("opened file 3f.00\n");
    else {
	if (read_rec(0, buf, 0x8) < 0)
	    printf("can't read 0.2\n", n);
	else {
	    printf("serial number 0.2: ");
	    dump_reply(buf, 0x8);
	    printf("\n");
	}
    }

    // open 1.0/1.1 (serial number?) 
    open_file(cmd, 0x3f, 0);
    if (open_file(cmd, 1, 0) < 0)
	printf("can't cd 1.0\n");
    if (open_file(cmd, 1, 1) < 0)
	printf("can't open 1.1\n");
    else {
	if (read_rec(0, buf, 0xa) < 0)
	    printf("can't read 1.1\n", n);
	else {
	    printf("serial number 1.1: ");
	    dump_reply(buf, 0xa);
	    printf("\n");
	}
    }

    open_file(cmd, 0x3f, 0);
    open_file(cmd, 2, 0);

    // open purse file 
    if (open_file(cmd, 2, 1) < 0)
	printf("can't open purse file\n");
    else {
	if (read_rec(0, buf, 0x6) < 0)
	    printf("can't read purse file\n", n);
	else {
	    printf("transaction %d; balance ", hex(buf));
	    dump_pennies(&buf[4]);
	    printf("\n");
	}
    }

    // open transaction log 
    if (open_file(cmd, 2, 2) < 0) {
	printf("can't open transaction log\n");
	goto efutz;
    }

    printf("Date        Time  Balance Transaction\n");
    if (print_rec(cmd, buf, 0) >= 0 && aflag)
	for (i = 1; i < 10; i++)
	    if (print_rec(cmd, buf, i) < 0)
		break;

    rtn = 0;
	*/
 efutz:
    len = stuff_cmd(EJECT, cmd);
    len = 0;
    SCBios(cmd, buf, &len, &r1, &r2);

 futz:
    SCBclose();
    exit(rtn);
}

read_rec(rn, buf, n)
int rn, n;
char *buf;
{
    char cmd[8];
    unsigned short len, r1, r2;

    cmd[0] = 2;
    cmd[1] = 0xb2;
    cmd[2] = rn + 1;
    cmd[3] = 4;
    cmd[4] = len = n;
    SCBios(cmd, buf, &len, &r1, &r2);
    if (r1 != 144 || r2 != 0) {
	printf("read: %x %x\n", r1, r2);
	return -1;
    }
    return 0;
}

print_rec(cmd, buf, n)
char *cmd, *buf;
int n;
{
    int c;

    if (read_rec(n, buf, 0xf) < 0) {
	printf("can't read transaction %d\n", n);
	return -1;
    }

    if (buf[0] == 0)
	/* empty record */
	return -1;

    switch (buf[14]) {
    case 0x4c:
	c = '+';
	break;
    case 0x49:
	c = 'I';
	break;
    case 0x50:
	c = '-';
	break;
    case 0x45:
    case 0x76:
	c = '>';
	break;
    default:
	c = '?';
	break;
    }

    /* don't bother with uninteresting records unless -v */
    if (!vflag && c == '>')
	return 0;

    dump_date(buf);
    printf("  %c", c);
    dump_pennies(&buf[6]);
    printf("  ");
    if (c == '?') {
	dump_reply(buf, 0xf);
	printf("  ");
    }
    dump_location(buf[9]);
    printf("\n");

    return 0;
}

dump_location(n)
int n;
{
    switch (n) {
    case 0x0:
	printf("ISSUED");
	break;
    case 0x16:
	printf("Argus 535 candy machine");
	break;
    case 0x18:
	printf("snack machine");
	break;
    case 0x19:
	printf("pop machine");
	break;
    case 0x22:
	printf("Buhr pop machine");
	break;
    case 0x23:
	printf("Buhr candy machine");
	break;
    case 0x36:
	printf("EECS pop machine");
	break;
    case 0x37:
	printf("EECS snack machine");
	break;
    case 0x79:
	printf("SAB");
	break;
    case 0x7d:
	printf("NC Commons");
	break;
    case 0x7e:
	printf("Union basement");
	break;
    default:
	printf("unknown location 0x%x", n);
	break;
    }
}

open_file(cmd, f0, f1)
char *cmd;
int f0, f1;
{
    char buf[4];
    unsigned short len, r1, r2;

    //cmd[0] = 1;
	//NI for CyberFlex JavaCard
	cmd[0] = CommandClass;
    cmd[1] = 0xa4;
    cmd[2] = 0;
    cmd[3] = 0;
    cmd[4] = len = 2;
    buf[0] = f0;
    buf[1] = f1;
    SCBios(cmd, buf, &len, &r1, &r2);
	// NI
	printf("SCBios() puts %x %x %x %x %x.%x %x\n returns %x %x\n", 
		cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], buf[0], buf[1],
		r1, r2);
		
    if (r1 != 144 || r2 != 0)
	return -1;
    return 0;
}

dump_date(buf)
char *buf;
{
    int month, year;

    year = bcd(buf[2]) + 1900;
    if (year < 1950)
	year += 100;

    month = bcd(buf[0]) - 1;
    if (month < 0 || month >= 12)
	month = 12;

    printf("%2d %s %d %2d:%02d ",
	   bcd(buf[1]),
	   monthtab[month],
	   year,
	   bcd(buf[3]),
	   bcd(buf[4]));
    dump_pennies(&buf[11]);
}

dump_pennies(buf)
char *buf;
{
    int pennies;

    pennies = hex(buf);
    printf("$%2d.%02d", pennies / 100, pennies % 100);
}

bcd(x)
int x;
{
    return (((x >> 4) & 0xf) * 10 + (x & 0xf));
}

hex(buf)
char *buf;
{
    return(((buf[0] & 0xff) << 8) + (buf[1] & 0xff));
}

dump_reply(p, n)
char *p;
int n;
{
    int i;

    for (i = 0; i < n; i++)
	printf("%02x ", p[i] & 0xff);
}

int ni_send(LPSTR str, int len)
{
	int i, rtn;
	for (i=0; i<len; i++){
		rtn = scsend(&str[i], 1, 1/*==NO_LRC*/) ;
	}
	return rtn;
}

int ni_recv()
{
	int rtn;
	char recv[2];

	rtn = screcv(recv, 2, 1/*==NO_LRC*/);
	//printf("%x.%x\n", recv[0], recv[1]);
	if (recv[0] != (char)0x90 || recv[1] != (char)0) return -1;
	else return 0;
}

int ni_select(char r0, char r1)
{
	char str[7];
	
	str[0] = 0xc0;
	str[1] = 0xa4;
	str[2] = 0x00;
	str[3] = 0x00;
	str[4] = 0x02;
	str[5] = r0;
	str[6] = r1;
	ni_send(str, 7);
	return ni_recv(); 
}

int ni_readbinary(int len, char *recv)
{
	char str[5];
	int i;
		
	str[0] = 0xf0;
	str[1] = 0xb0;
	str[2] = 0x00;
	str[3] = 0x00;
	str[4] = len;
	
	ni_send(str, 5);
	// the first byte of reply is command number (0xb0).
	screcv(recv, 1, 1);
	screcv(recv, len, 1/*==NO_LRC*/);
	//printf("%x.%x\n", recv[0], recv[1]);
	for (i=0; i<len; i++){
		recv[i] = recv[i] & 0xff;
		printf("%x ", recv[i]);
	}
	puts("");
	return 0;
}

int ni_writebinary(LPSTR send_data, int len)
{
	int i;
	char str[5+MaxStrLen];

	str[0] = 0xf0;
	str[1] = 0xd6;
	str[2] = 0x00;
	str[3] = 0x00;
	str[4] = len;
	
	for (i=0; i<len; i++){
		str[5+i] = send_data[i];
	}

	ni_send(str, 5+len);
	return ni_recv(); 
}
