#include "GlobHdr.h"
#include "IReader.h"
#include "Desc.h"
#include "Log.h"

#include <stdio.h>

typedef struct
{
	Desc    desc;
	int     free;
} FromData;

/*--------------
 * FromDesc_Open
 */

static const _kernel_oserror* FromDesc_Open(IStream* s, const _kernel_swi_regs* r)
{
	Desc* desc = (Desc*) r->r[0];
	FromData* fd;
	const _kernel_oserror* e;

	e = IStream_Alloc(s, (void**) &fd, sizeof(*fd));
	if (e) return e;

	s->reader.data = fd;
	fd->desc = *desc;
	fd->free = 0;

	if (fd->desc.flags & DiskSample_Desc_UseTypeString)
	{
		e = IStream_Accept(s, &fd->desc);
		if (e) return e;
	}
	else
	{
		s->source.os_filetype = (int) fd->desc.filetype;
	}

	s->source.end = s->source.length = fd->desc.filesize;

	s->state = EIStream_State_MetaDataLookup;

	return NULL;
}

/*-----------------
 * FromDesc_DelayIO
 */

static bool FromDesc_DelayIO(IStream* s)
{
	IGNORE(s);

	return false;
}

/*--------------
 * FromDesc_Fill
 */

static const _kernel_oserror* FromDesc_Fill(IStream* s)
{
	FromData* fd = s->reader.data;
	int ioff = _kernel_irqs_disabled();
	int used;

	if (!ioff) _kernel_irqs_off();
	used = s->inb->free - fd->free;
	if (used < 0) used += s->inb->size;
	fd->free = s->inb->free;
	if (!ioff) _kernel_irqs_on();

	s->source.pos += used;

	return NULL;
}

/*----------------
 * FromDesc_SetPos
 */

static const _kernel_oserror* FromDesc_SetPos(IStream* s, int pos)
{
	FromData* fd = s->reader.data;

    // The function is defined so that the stream is seen as positionable
    // and allow to clear the input/output buffers.
	fd->free = s->inb->free;
	s->source.pos = pos;

	return NULL;
}

/*---------------
 * FromDesc_Close
 */

static const _kernel_oserror* FromDesc_Close(IStream* s)
{
	FromData* fd = s->reader.data;

	if (!fd) return NULL;

	IStream_Free(s, &s->reader.data);

	return NULL;
}

IReader FromDesc =
{
	  "Desc"
	, FromDesc_Open
	, FromDesc_DelayIO
	, FromDesc_Fill
	, NULL
	, FromDesc_SetPos
	, FromDesc_Close
};
