/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */

#include <malloc.h>
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "sector.h"
#include "libburn.h"
#include "drive.h"
#include "transport.h"
#include "message.h"
#include "crc.h"
#include "debug.h"
#include "init.h"
#include "lec.h"
#include "toc.h"
#include "util.h"
#include "sg.h"
#include "read.h"
#include "options.h"

void burn_disc_read(struct burn_drive *d, const struct burn_read_opts *o)
{
#if 0
	int i, end, maxsects, finish;
	int seclen;
	int drive_lba;
	unsigned short crc;
	unsigned char fakesub[96];
	struct buffer page;
	int speed;

	assert((o->version & 0xfffff000) == (OPTIONS_VERSION & 0xfffff000));

	assert(!d->busy);
	assert(d->toc->valid);
	assert(o->datafd != -1);
/* XXX not sure this is a good idea.  copy it? */
/* XXX also, we have duplicated data now, do we remove the fds from struct 
drive, or only store a subset of the _opts structs in drives */

	/* set the speed on the drive */
	speed = o->speed > 0 ? o->speed : d->mdata->max_read_speed;
	d->set_speed(d, speed, 0);

	d->params.retries = o->hardware_error_retries;
	d->send_parameters(d, o);

	d->cancel = 0;
	d->busy = BURN_DRIVE_READING;
	d->currsession = 0;
/*	drive_lba = 232000;
	d->currtrack = 18;
*/
	d->currtrack = 0;
	drive_lba = 0;
/* XXX removal of this line obviously breaks *
   d->track_end = burn_track_end(d, d->currsession, d->currtrack);*/
	printf("track ends at %d\n", d->track_end);
	page.sectors = 0;
	page.bytes = 0;

	if (o->subfd != -1) {
		memset(fakesub, 0xFF, 12);
		memset(fakesub + 12, 0, 84);
		fakesub[13] = 1;
		fakesub[14] = 1;
		fakesub[20] = 2;
		fakesub[12] = (d->toc->toc_entry[0].control << 4) +
			d->toc->toc_entry[0].adr;
		crc = crc_ccitt(fakesub + 12, 10);
		fakesub[22] = crc >> 8;
		fakesub[23] = crc & 0xFF;
		write(o->subfd, fakesub, 96);
	}
	while (1) {
		seclen = burn_sector_length_read(d, o);

		burn_print(12, "received %d blocks\n", page.sectors);
		for (i = 0; i < page.sectors; i++) {
			burn_packet_process(d, page.data + seclen * i, o);
			d->track_end--;
			drive_lba++;
		}

		if ((d->cancel) || (drive_lba == LAST_SESSION_END(d))) {
			burn_print(1, "finished or cancelled\n");
			d->busy = BURN_DRIVE_IDLE;
			if (!d->cancel)
				d->toc->complete = 1;
			return;
		}
/* XXX: removal of this line obviously breaks *
		end = burn_track_end(d, d->currsession, d->currtrack); */

		if (drive_lba == end) {
			d->currtrack++;
			if (d->currtrack >
			    d->toc->session[d->currsession].lasttrack) {
				d->currsession++;
				burn_print(12, "session switch to %d\n",
					   d->currsession);
				burn_print(12, "skipping a lead out\n");
				drive_lba = CURRENT_SESSION_START(d);
				burn_print(12, "new lba %d\n", drive_lba);
/* XXX more of the same
				end = burn_track_end(d, d->currsession,
							d->currtrack);
*/ }
			burn_print(12, "track switch to %d\n", d->currtrack);
		}

		page.sectors = 0;
		page.bytes = 0;

		maxsects = BUFFER_SIZE / seclen;
		finish = end - drive_lba;

		d->track_end = finish;

		page.sectors = (finish < maxsects) ? finish : maxsects;
		printf("reading %d sectors from %d\n", page.sectors,
		       drive_lba);
		d->read_sectors(d, drive_lba, page.sectors, o, &page);
		printf("Read %d\n", page.sectors);
	}
#endif
}
int burn_sector_length_read(struct burn_drive *d,
			    const struct burn_read_opts *o)
{
	int dlen = 2352;
	int data;

/*XXX how do we handle this crap now?*/
/*	data = d->toc->track[d->currtrack].toc_entry->control & 4;*/
	data = 1;
	if (o->report_recovered_errors)
		dlen += 294;
	if ((o->subcodes_data) && data)
		dlen += 96;
	if ((o->subcodes_audio) && !data)
		dlen += 96;
	return dlen;
}

static int bitcount(unsigned char *data, int n)
{
	int i, j, count = 0;
	unsigned char tem;

	for (i = 0; i < n; i++) {
		tem = data[i];
		for (j = 0; j < 8; j++) {
			count += tem & 1;
			tem >>= 1;
		}
	}
	return count;
}

void burn_packet_process(struct burn_drive *d, unsigned char *data,
			 const struct burn_read_opts *o)
{
	unsigned char sub[96];
	unsigned short crc;
	int ptr = 2352, i, j, code, fb;
	int audio = 1;

	if (o->c2errors) {
		fb = bitcount(data + ptr, 294);
		if (fb) {
			burn_print(1, "%d damaged bits\n",
				   bitcount(data + ptr, 294));
			burn_print(1, "sending error on %s %s\n",
				   d->idata->vendor, d->idata->product);
			/* XXX send a burn_message! burn_message_error(d,
			   something); */
		}
		ptr += 294;
	}
/*
	if (d->toc->track[d->currtrack].mode == BURN_MODE_UNINITIALIZED) {
		if ((d->toc->track[d->currtrack].toc_entry->control & 4) == 0)
			d->toc->track[d->currtrack].mode = BURN_MODE_AUDIO;
		else
			switch (data[15]) {
			case 0:
				d->toc->track[d->currtrack].mode = BURN_MODE0;
				break;
			case 1:
				d->toc->track[d->currtrack].mode = BURN_MODE1;
				break;
			case 2:
				d->toc->track[d->currtrack].mode =
					BURN_MODE2_FORMLESS;
				break;
			}
	}
*/
	if ((audio && o->subcodes_audio)
	    || (!audio && o->subcodes_data)) {
		memset(sub, 0, sizeof(sub));
		for (i = 0; i < 12; i++) {
			for (j = 0; j < 8; j++) {
				for (code = 0; code < 8; code++) {
					sub[code * 12 + i] <<= 1;
					if (data[ptr + j + i * 8] &
					    (1 << (7 - code)))
						sub[code * 12 + i]++;
				}
			}
		}
		crc = (*(sub + 22) << 8) + *(sub + 23);
		if (crc != crc_ccitt(sub + 12, 10)) {
			burn_print(1, "sending error on %s %s\n",
				   d->idata->vendor, d->idata->product);
/*			e = burn_error();
			e->drive = d;
*/
			burn_print(1, "crc mismatch in Q\n");
		}
		/* else process_q(d, sub + 12); */
		/* 
		   if (o->subfd != -1) write(o->subfd, sub, 96); */
	}
/*
	if ((d->track_end <= 150)
	    && (drive_lba + 150 < CURRENT_SESSION_END(d))
	    && (TOC_ENTRY(d->toc, d->currtrack).control == 4)
	    && (TOC_ENTRY(d->toc, d->currtrack + 1).control == 0)) {
		burn_print(12, "pregap : %d\n", d->track_end);
		write(o->binfd, zeros, 2352);

#warning XXX WHERE ARE MY SUBCODES
				} else
*//* write(o->datafd, data, 2352); */
}

/*  so yeah, when you uncomment these, make them write zeros insted of crap
static void write_empty_sector(int fd)
{
	char sec[2352];

	burn_print(1, "writing an 'empty' sector\n");
	write(fd, sec, 2352);
}

static void write_empty_subcode(int fd)
{
	char sub[96];

	write(fd, sub, 96);
}

static void flipq(unsigned char *sub)
{
	*(sub + 12 + 10) = ~*(sub + 12 + 10);
	*(sub + 12 + 11) = ~*(sub + 12 + 11);
}
*/
