#include <../source/TAL/objbase.h>
#include <../source/vfs/iobase.h>
#include <../source/vfs/np_priv.h>

typedef struct private_pipe_s
{
	ioport_base_t	vtbl;
	u8_fifo_t		buffer;
	char			pipe_name[_MAX_PATH];
}	private_pipe_t, *private_pipe_p;

V_LOCAL vsize_t	V_CALL
read_private_pipe(vhandle_t handle,void *buf,vsize_t len)
{
	private_pipe_p self = (private_pipe_p)handle;
	if(len > u8fCount(&self->buffer))
		len = u8fCount(&self->buffer);
	if(len)
		u8fPopBuffer(&self->buffer,(u8_p)buf,len);
	return len;
}

V_LOCAL vsize_t	V_CALL
write_private_pipe(vhandle_t handle,void *buf,vsize_t len)
{
	private_pipe_p self = (private_pipe_p)handle;
	u8fPushBuffer(&self->buffer,(u8_p)buf,len);
	return len;
}

V_LOCAL int	V_CALL
control_private_pipe(vhandle_t handle,unsigned code,void *parameters)
{
	private_pipe_p self = (private_pipe_p)handle;
	switch(code)
	{
		case pctl_get_name:
			if(parameters)
			{
				strCopy((char*)parameters,self->pipe_name,_MAX_PATH);
				return 0;
			}
			return -1;
		case pctl_get_type:
        	if(!parameters)
            	return -1;
           	*((u32_t*)parameters) = 0;
            return 0;
		case pctl_get_size:
        	if(!parameters)
            	return -1;
           	*((u32_t*)parameters) = u8fCount(&self->buffer);
            return 0;
		case pctl_is_eof:
        	if(!parameters)
            	return -1;
           	*((vboolean*)parameters) = u8fCount(&self->buffer) ? false : true;
            return 0;
		case pctl_pipe_head_len:
        	if(!parameters)
            	return -1;
           	RBF_CHAIN1_LEN(&(self->buffer),*((vsize_t*)parameters));
			return 0;
		case pctl_pipe_tail_len:
        	if(!parameters)
            	return -1;
			RBF_CHAIN2_LEN(&self->buffer,*((vsize_t*)parameters));
			return 0;
		case pctl_pipe_head:
        	if(!parameters)
            	return -1;
			*((void**)parameters) = RBF_CHAIN1(&self->buffer);
			return 0;
		case pctl_pipe_tail:
        	if(!parameters)
            	return -1;
			*((void**)parameters) = RBF_CHAIN2(&self->buffer);
			return 0;
		default:
			break;
	}
	return -1;
}

V_LOCAL vsize_t V_CALL
seek_private_pipe(vhandle_t handle,vssize_t offset,int whence)
{
	private_pipe_p self = (private_pipe_p)handle;
	if(whence != SEEK_SET || offset)
	{
#ifdef	CHECKED_BUILD
		conlPuts(LOG_ERROR,"seek_private_pipe(): only truncation allowed.\n");
#endif	/* CHECKED_BUILD */
		return INVALID_IO_OFFSET;
	}
	u8fPurge(&self->buffer);
	return 0;
}

V_LOCAL u32_t V_CALL
destroy_private_pipe(vhandle_t handle)
{
	private_pipe_p self = (private_pipe_p)handle;
	UNREF_EXIT(&self->vtbl);
#ifdef	CHECKED_BUILD
	if(u8fCount(&self->buffer))
		conlPrintf(LOG_WARNING,
			"destroy_private_pipe(): %u bytes lost.\n",
			u8fCount(&self->buffer));
#endif	/* CHECKED_BUILD */
	u8fClear(&self->buffer);
	memFreeObject(self);
	return 0;
}

vhandle_t	V_CALL
ioCreatePrivatePipe(char *pipe_name)
{
	private_pipe_p self = (private_pipe_p)ioAllocPort(sizeof(private_pipe_t));
    self->vtbl.base.destroy = destroy_private_pipe;
	self->vtbl.read = read_private_pipe;
	self->vtbl.write = write_private_pipe;
	self->vtbl.ioctl = control_private_pipe;
	self->vtbl.seek = seek_private_pipe;
	u8fInit(&self->buffer);
	if(pipe_name)
		strCopy(self->pipe_name,pipe_name,_MAX_PATH);
	else
		self->pipe_name[0] = 0;
	return self;
}
