#include "internal.h"
#define ifd_msleep(x) usleep(x * 1000)

#include <string.h>

static int anysee_open(ifd_reader_t *reader, const char *device_name)
{ 
	ifd_device_t *dev;
	ifd_device_params_t params;
	ifd_debug(1, "%s: dev:%s", __func__, device_name);

	reader->name = "Anysee DVB USB card reader";
	reader->nslots = 1;
	if (!(dev = ifd_device_open(device_name)))
		return -1;
	reader->device = dev;

	if (ifd_device_type(dev) != IFD_DEVICE_TYPE_SERIAL) {
		ct_error("test driver: device %s is not a USB device", device_name);
		ifd_device_close(dev);
		return -1;
	}

	if (dev->type == IFD_DEVICE_TYPE_SERIAL) {
		if (ifd_device_get_parameters(dev, &params) < 0)
			return -1;

		params.serial.speed = 9600;
		params.serial.bits = 8;
		params.serial.stopbits = 1;
		params.serial.parity = IFD_SERIAL_PARITY_NONE;
		params.serial.dtr = 1;
		params.serial.rts = 1;

		if (ifd_device_set_parameters(dev, &params) < 0)
			return -1;
	}
//	dev->user_data = (void *)privd;
//	dev->timeout = TIMEOUT;
//	return 0;

	reader->device = dev;
	dev->timeout = 1000;

	return 0;
}

static int anysee_close(ifd_reader_t * reader)
{
	ifd_debug(1, "%s:", __func__);
	return 0;
}

static int anysee_cmd(ifd_reader_t *reader, void *sbuf, size_t slen, void *rbuf, size_t rlen)
{
	int ret;
	uint8_t buf[60];
//	buf[0] = 0x34;

	ret = ifd_device_send(reader->device, sbuf, slen);
	ret = ifd_device_recv(reader->device, buf, 60, 100);

	ret = 0;

	/* read request, copy returned data to return buf */
	if (!ret && rbuf && rlen)
		memcpy(rbuf, buf, rlen);

	return 0;
}

static int anysee_activate(ifd_reader_t *reader)
{
	int i, ret;
	uint8_t sbuf[][14] = {
		{0x34,0x03,0x01,0x00,0xaf,0x00,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x01,0x10,0x08,0x00,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x01,0x20,0x08,0x00,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x01,0x11,0x4c,0x00,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x01,0x21,0x4c,0x00,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x02,0x17,0x00,0x4b,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x02,0x27,0x00,0x4b,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x02,0x1c,0x0f,0xa4,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x02,0x2c,0x0f,0xa4,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x01,0x11,0x4c,0xa4,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x01,0x21,0x4c,0xa4,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x01,0x1b,0x00,0xa4,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x03,0x01,0x2b,0x00,0xa4,0x01,0x80,0x08,0xb6,0x60,0xa9,0x08,0xb6},
		{0x34,0x00,0x01,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
		{0x34,0x01,0x01,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
		{0x34,0x00,0x01,0x05,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
		{0x34,0x01,0x01,0x05,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
		{0x34,0x02,0x01,0x10,0x20,0xfd,0x20,0x0e,0xf8,0x0c,0xc7,0xaa,0xe2,0x10},
		{0x34,0x02,0x01,0x11,0x01,0x00,0x00,0x00,0xb8,0xb5,0xb8,0x81,0x00,0x00},
		{0x34,0x03,0x01,0x11,0x4c,0x00,0x00,0x00,0xb8,0xb5,0xb8,0x81,0x00,0x00},
		{0x34,0x02,0x01,0x11,0xcc,0xc9,0x24,0x5b,0x38,0x1a,0xc8,0x01,0x01,0x00},
		{0x34,0x03,0x01,0x11,0x4c,0xc9,0x24,0x5b,0x38,0x1a,0xc8,0x01,0x01,0x00},
	};
	ifd_debug(1, "%s:", __func__);

//	for (i = 0; i < 47; i++) {
	for (i = 0; i < 22; i++) {
		ret = anysee_cmd(reader, sbuf[i], 14, NULL, 0);
		if (ret)
			goto error;

	}

error:
	return ret;
}

static int anysee_deactivate(ifd_reader_t * reader)
{
	ifd_debug(1, "%s:", __func__);
	return 0;
}

static int anysee_change_parity(ifd_reader_t * reader, int parity)
{
	ifd_debug(1, "%s: parity:%d", __func__, parity);
	return 0;
}

static int anysee_change_speed(ifd_reader_t * reader, 
                               unsigned int speed)
{
	ifd_debug(1, "%s: speed:%d", __func__, speed);
	return 0;
}

static int anysee_card_reset(ifd_reader_t *reader, int slot, void *atr, size_t atr_len)
{
	ifd_debug(1, "%s: slot:%d atr_len:%d", __func__, slot, atr_len);
	int ret, i, j;
	// Card ATR: 3B 24 00 30 42 30 30
	uint8_t atr_buf[atr_len], len;
	unsigned char rbuf2[64];
	unsigned char sbuf2[][14] = {
		{0x34,0x03,0x01,0x1b,0x00,0x08,0x5b,0x80,0x20,0xd8,0x67,0x81,0xd0,0xe3},
		{0x34,0x03,0x01,0x13,0x00,0xb9,0x5f,0xa9,0xa5,0x08,0x5b,0x80,0xd0,0xe3},
		{0x34,0x03,0x01,0x14,0x11,0xb9,0x5f,0xa9,0xa5,0x08,0x5b,0x80,0xd0,0xe3},
		{0x34,0x03,0x01,0x15,0x0a,0xb9,0x5f,0xa9,0xa5,0x08,0x5b,0x80,0xd0,0xe3},
		{0x34,0x03,0x02,0x19,0x00,0x00,0x5f,0xa9,0xa5,0x08,0x5b,0x80,0xd0,0xe3},
		{0x34,0x01,0x01,0x02,0x00,0x00,0x5f,0xa9,0xa5,0x08,0x5b,0x80,0xd0,0xe3},
		{0x34,0x02,0x01,0x10,0x38,0x1a,0xc8,0x01,0x01,0x00,0x00,0x00,0x00,0x00},
		{0x34,0x03,0x01,0x10,0x08,0x1a,0xc8,0x01,0x01,0x00,0x00,0x00,0x00,0x00},
		{0x34,0x02,0x01,0x10,0x08,0x1a,0xc8,0x01,0x01,0x00,0x00,0x00,0x00,0x00},
		{0x34,0x03,0x01,0x10,0x09,0x1a,0xc8,0x01,0x01,0x00,0x00,0x00,0x00,0x00},
		{0x34,0x03,0x01,0x1b,0x77,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x81,0xb9},
		{0x34,0x08,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
	};

	uint8_t sbuf_rst[][10] = {
		{0x34,0x03,0x01,0x1b,0x00,0x08,0x5b,0x80,0x20,0xd8},
		{0x34,0x03,0x01,0x13,0x00,0xb9,0x5f,0xa9,0xa5,0x08},
		{0x34,0x03,0x01,0x14,0x11,0xb9,0x5f,0xa9,0xa5,0x08},
		{0x34,0x03,0x01,0x15,0x0a,0xb9,0x5f,0xa9,0xa5,0x08},
		{0x34,0x03,0x02,0x19,0x00,0x00,0x5f,0xa9,0xa5,0x08},
		{0x34,0x01,0x01,0x02,0x00,0x00,0x5f,0xa9,0xa5,0x08},
		{0x34,0x02,0x01,0x10,0x38,0x1a,0xc8,0x01,0x01,0x00},
		{0x34,0x03,0x01,0x10,0x08,0x1a,0xc8,0x01,0x01,0x00},
		{0x34,0x02,0x01,0x10,0x08,0x1a,0xc8,0x01,0x01,0x00},
		{0x34,0x03,0x01,0x10,0x09,0x1a,0xc8,0x01,0x01,0x00},
		{0x34,0x03,0x01,0x1b,0x77,0x00,0x02,0x00,0x00,0x00},
		{0x34,0x08,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00},
	};

	uint8_t sbuf[3], rbuf[2+1];
	sbuf[0] = 0x34;
	sbuf[1] = 0x06;
	sbuf[2] = 0x01;

	/* perform reset */
	for (i = 0; i < 12; i++)
		ret = anysee_cmd(reader, sbuf_rst[i], 7, NULL, 0);


//	for (i = 0; i < 12; i++) {
//		ret = anysee_cmd(reader, sbuf2[i], 14, NULL, 0);
//	}

	/* read ATR */
	for (i = 0, j = 0, len = 2; i < 300 && j < len; i++) {
		ifd_msleep(1);
		ret = anysee_cmd(reader, sbuf, sizeof(sbuf), rbuf, sizeof(rbuf));
		if (rbuf[0] == 0x01) {
			if (j == 1) {
				/* calc ATR len */
				len += rbuf[2] & 0x0f;
				if (rbuf[2] & (1 << 4))
					len++;
				if (rbuf[2] & (1 << 5))
					len++;
				if (rbuf[2] & (1 << 6))
					len++;
				if (rbuf[2] & (1 << 7))
					len++;
			}
			atr_buf[j++] = rbuf[2];
		}
	}
	if (len == j) {
		memcpy(atr, atr_buf, len);
		ret = len;
	} else {
		ret = IFD_ERROR_INVALID_ATR;
	}
	return ret;
}

static int anysee_card_status(ifd_reader_t *reader, int slot,  int *status)
{
	int ret;
	uint8_t sbuf[] = {0x34, 0x02, 0x01, 0x10};
	uint8_t rbuf[1];
	ifd_debug(1, "%s: slot:%d", __func__, slot);

	ret = anysee_cmd(reader, sbuf, sizeof(sbuf), rbuf, sizeof(rbuf));
	if (ret)
		goto error;

	if (rbuf[0] & (1 << 7))
		*status = 0;
	else
		*status = IFD_CARD_PRESENT;

error:
	return ret;
}

static int anysee_send(ifd_reader_t *reader, unsigned int dad, const unsigned char *buffer, size_t len)
{
	ifd_debug(1, "%s: dad:%d len:%d", __func__, dad, len);
	ifd_debug(3, "data:%s", ct_hexdump(buffer, len));
	int ret;
	uint8_t sbuf[3+len], sbuf2[] = {0x34, 0x08, 0x01, 0x01, 0x00, len};
	sbuf[0] = 0x34;
	sbuf[1] = 0x07; // cmd
	sbuf[2] = len;
	memcpy(&sbuf[3], buffer, len);

	ret = anysee_cmd(reader, sbuf2, sizeof(sbuf2), NULL, 0);
	ret = anysee_cmd(reader, sbuf, sizeof(sbuf), NULL, 0);

	return 0;
}

static int anysee_recv(ifd_reader_t *reader, unsigned int dad,
	unsigned char *buffer, size_t len, long timeout)
{
	ifd_debug(1, "%s: dad:%d len:%d timeout:%d", __func__, dad, len, timeout);
	int ret, i;
	uint8_t sbuf[3], rbuf[2+len];
	uint8_t quotient, remainder, msg_len;
	sbuf[0] = 0x34;
	sbuf[1] = 0x06;
	sbuf[2] = len;

#if 0
#define MAX_LEN 48
	quotient = len / MAX_LEN;
	remainder = len % MAX_LEN;
	msg_len = MAX_LEN;
	for (i = 0; (i <= quotient && remainder); i++) {
		if (i == quotient)  /* set len of the last msg */
			msg_len = remainder;

			ret = anysee_cmd(reader, sbuf, sizeof(sbuf), rbuf, sizeof(rbuf));
			if (rbuf[0]) {
				memcpy(&buffer[i*MAX_LEN], &rbuf[2], msg_len);
			}

		msg[0].len = msg_len + 1;
		buf[0] = reg + i * msg_len_max;
		memcpy(&buf[1], &val[i * msg_len_max], msg_len);

		ret = i2c_transfer(priv->i2c, msg, 1);
		if (ret != 1)
			break;
	}
//	uint8_t tmp[] = {0x32,0x2f,0xe0,0x10,0x01,0x0f,0x4b,0x61,0x61,0x70,0x65,0x6c,0x69,0x6b,0x6f,0x72,0x74,0x74,0x69,0x20,0x20,0x30,0x02,0x21,0x7b,0x30,0x02,0x3e,0x7b,0x20,0x04,0x01,0x00,0x00,0x01,0x30,0x02,0x01,0x01,0x30,0x02,0x01,0x01,0x20,0x04,0x00,0x00,0x00,0x00,0x90,0x00};

#endif

// 22 OK, 23 NOK ==> MAX 48
#define COUNT 22
	

	if (len == 51) {

		len = 26 + COUNT;
		sbuf[2] = len;
		for (i = 0; i < 100; i++) {
			ret = anysee_cmd(reader, sbuf, sizeof(sbuf), rbuf, sizeof(rbuf));
			if (rbuf[0]) {
				memcpy(buffer, &rbuf[2], len);
				break;
			}
			ifd_msleep(100);
		}

		len = 25 - COUNT;
		sbuf[2] = len;
		for (i = 0; i < 100; i++) {
			ret = anysee_cmd(reader, sbuf, sizeof(sbuf), rbuf, sizeof(rbuf));
			if (rbuf[0]) {
				memcpy(&buffer[26 + COUNT], &rbuf[2], len);
				break;
			}
			ifd_msleep(100);
		}

	} else {



	for (i = 0; i < 100; i++) {
		ret = anysee_cmd(reader, sbuf, sizeof(sbuf), rbuf, sizeof(rbuf));
		if (rbuf[0]) {
			memcpy(buffer, &rbuf[2], len);
			break;
		}
		ifd_msleep(100);
	}

	}

	return 0;
}

static struct ifd_driver_ops anysee_driver;

void ifd_anysee_register(void)
{
        anysee_driver.open = anysee_open;
        anysee_driver.close = anysee_close;
        anysee_driver.activate = anysee_activate;
        anysee_driver.deactivate = anysee_deactivate;
        anysee_driver.card_reset = anysee_card_reset;
        anysee_driver.card_status = anysee_card_status;
//        anysee_driver.change_parity = anysee_change_parity;
//        anysee_driver.change_speed = anysee_change_speed;
        anysee_driver.send = anysee_send;
        anysee_driver.recv = anysee_recv;
        ifd_driver_register("anysee", &anysee_driver);
}

