/********************************************
libmawk (C) 2014, Tibor 'Igor2' Palinkas;

This is a source file for libmawk, an implementation of
the AWK programming language, fork of mawk.

Libmawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
#include "vio_fifo.h"
#include "memory.h"

const mawk_vio_imp_t mawk_vio_fifo_imp;

mawk_vio_t *mawk_vio_fifo_open(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode)
{
	mawk_vio_fifo_t *v;
	v = mawk_zmalloc(MAWK, sizeof(mawk_vio_fifo_t));
	v->eof_from_awk = 0;
	v->eof_from_app = 0;
	v->vio_common_head.imp = &mawk_vio_fifo_imp;
	v->vio_common_head.refco = 0;
	mawk_zfifo_alloc(MAWK, &(v->fifo), -1);
	switch(mode) {
		case MAWK_VIO_O_TRUNC:
		case MAWK_VIO_O_APPEND:
			v->is_awk2app = 1;
			break;
		case MAWK_VIO_I:
			v->is_awk2app = 0;
			break;
	}
	return (mawk_vio_t *)v;
}

/* write data to a vio * */
int mawk_vio_fifo_putc(mawk_state_t *MAWK, mawk_vio_t *vf, char c)
{
	mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
	if (!v->is_awk2app)
		return -1;
	return mawk_zfifo_write(MAWK, &(v->fifo), &c, 1);
}

int mawk_vio_fifo_write_str(mawk_state_t *MAWK, mawk_vio_t *vf, const char *str)
{
	mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
	int len = strlen(str);

	if (!v->is_awk2app)
		return -1;

	return mawk_zfifo_write(MAWK, &(v->fifo), str, len);
}

int mawk_vio_fifo_write_app(mawk_state_t *MAWK, mawk_vio_t *vf, const char *data, int len)
{
	mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
	if (v->is_awk2app)
		return -1;
	return mawk_zfifo_write(MAWK, &(v->fifo), data, len);
}

int mawk_vio_fifo_write(mawk_state_t *MAWK, mawk_vio_t *vf, const char *data, int len)
{
	mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
	if (!v->is_awk2app)
		return -1;
	return mawk_zfifo_write(MAWK, &(v->fifo), data, len);
}

int mawk_vio_fifo_printf(mawk_state_t *MAWK, mawk_vio_t *vf, const char *fmt, ...)
{
	mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
	if (!v->is_awk2app)
		return -1;
TODO("TODO")
	abort();
	return -1;
}


int mawk_vio_fifo_read(mawk_state_t *MAWK, mawk_vio_t *vf, char *dst, long int size)
{
	mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
	int len;

	if (v->is_awk2app)
		return -1;

	len = mawk_zfifo_read(MAWK, &(v->fifo), dst, size);
	if (len == 0) {
		/* there's no more data and the app has finished: pass on eof */
		if (v->eof_from_app)
			return 0;

		/* there's no more data at the moment, but the app didn't say eof yet */
		return -2;
	}

	return len;
}

int mawk_vio_fifo_read_app(mawk_state_t *MAWK, mawk_vio_t *vf, char *dst, long int size)
{
	mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;
	int len;

	if (!v->is_awk2app)
		return -1;

	len = mawk_zfifo_read(MAWK, &(v->fifo), dst, size);
	if (len == 0) {
		/* there's no more data and the app has finished: pass on eof */
		if (v->eof_from_awk)
			return 0;

		/* there's no more data at the moment, but the app didn't say eof yet */
		return -2;
	}

	return len;
}

static void close_on_eof(mawk_state_t *MAWK, mawk_vio_fifo_t *v)
{
	if ((v->eof_from_app) && (v->eof_from_awk)) {
		mawk_zfifo_free(MAWK, &(v->fifo));
		mawk_zfree(MAWK, v, sizeof(mawk_vio_fifo_t));
	}
}


int mawk_vio_fifo_close(mawk_state_t *MAWK, mawk_vio_t *vf)
{
	mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;

	v->eof_from_awk = 1;
	close_on_eof(MAWK, v);
	return 0;
}

int mawk_vio_fifo_eof_from_app(mawk_state_t *MAWK, mawk_vio_t *vf)
{
	mawk_vio_fifo_t *v = (mawk_vio_fifo_t *)vf;

	v->eof_from_app = 1;
	close_on_eof(MAWK, v);
	return 0;
}

int mawk_vio_fifo_flush(mawk_state_t *MAWK, mawk_vio_t *vf)
{
	/* nothing to do on flush */
	return 0;
}

int mawk_vio_fifo_error(mawk_state_t *MAWK, mawk_vio_t *vf)
{
	return (vf == NULL);
}

void mawk_vio_fifo_mark_no_close(mawk_state_t *MAWK, mawk_vio_t *vf)
{
	/* fifos are always closed when both awk and the app closes them and
	   there are no inherited pipes anyway */
}

const mawk_vio_imp_t mawk_vio_fifo_imp = {
	mawk_vio_fifo_putc,
	mawk_vio_fifo_write_str,
	mawk_vio_fifo_write,
	mawk_vio_fifo_printf,
	mawk_vio_fifo_read,
	mawk_vio_fifo_close,
	mawk_vio_fifo_flush,
	mawk_vio_fifo_error,
	mawk_vio_fifo_mark_no_close
};
