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

#ifdef	CHECKED_BUILD

/*
**	Note: IOPORT_MAGIC #define'd in iobase.h
*/

V_LOCAL char			*ioport_name="i/o port";

V_LOCAL	char *stub_warning_fmt="file->vtbl->%s(): method undefined.\n";
#define COMPLAIN_STUB(caller) \
		conlPrintf(LOG_ERROR,stub_warning_fmt,(caller));

#else	/* !CHECKED_BUILD */

#define COMPLAIN_STUB(caller)

#endif	/* !CHECKED_BUILD */

#include <../source/PAL/argsused.h>
u32_t	V_CALL
io_read_stub(void *object,void *buf,u32_t len)
{
	COMPLAIN_STUB("read");
	return 0;	/* nothing to read */
}

#include <../source/PAL/argsused.h>
u32_t	V_CALL
io_write_stub(void *object,void *buf,u32_t len)
{
	COMPLAIN_STUB("write");
	return 0;	/* no destination to write to */
}

#include <../source/PAL/argsused.h>
u32_t	V_CALL
io_seek_stub(void *object,s32_t offset,int whence)
{
	COMPLAIN_STUB("seek");
	return INVALID_IO_OFFSET;
}

#include <../source/PAL/argsused.h>
u32_t	V_CALL
io_tell_stub(void *object)
{
	COMPLAIN_STUB("tell");
	return INVALID_IO_OFFSET;
}

#include <../source/PAL/argsused.h>
int		V_CALL
io_control_stub(void *object,int code,void *parameters)
{
	COMPLAIN_STUB("ioctl");
	return -1;	/* error condition: all codes unknown */
}

V_LOCAL u32_t V_CALL
ioport_destroy(void *object)
{
	ioport_base_p port=(ioport_base_p)object;
    if(--port->base.ref_count)
    	return port->base.ref_count;
	memFreeObject(object);
	return 0;
}

/*
 *		ioAllocPort(): returns object which can nothing except
 *	destroy itself. Normally used for creation of descendant
 *	objects; in later case, 'size_of_real_port' must be equal
 *	to sizeof(descendant).
 */
file_t	V_CALL
ioAllocPort(u32_t size_of_real_port)
{
	ioport_base_p port;
    if(!size_of_real_port)
    {
#ifdef	CHECKED_BUILD
		conlPuts(LOG_WARNING,
        	"ioAllocPort(0): using sizeof(ioport_base_t).\n");
#endif	/* CHECKED_BUILD */
    	size_of_real_port=sizeof(ioport_base_t);
	}
	ALLOC_OBJECT(port,ioport_base_t,
		size_of_real_port-sizeof(ioport_base_t),IOPORT_MAGIC);
	port->base.destroy=ioport_destroy;
    port->read=io_read_stub;
	port->write=io_write_stub;
	port->seek=io_seek_stub;
	port->tell=io_tell_stub;
	port->ioctl=io_control_stub;
	return (file_t)port;
}

/*
 *	Global functions to operate with io ports
 */
u32_t	V_GLOBAL
fileRead(void_p handle,void *buf,u32_t len)
{
	if(!libvIsHandle((void*)handle,"fileRead",ioport_name,IOPORT_MAGIC))
		return 0;
	if(!buf || !len)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,
			"fileRead(%X,%X,%d): incorrect destination.\n",
			handle,buf,len);
#endif	/* CHECKED_BUILD */
		return 0;
	}
	return ((ioport_base_t*)handle)->read(handle,buf,len);
}

u32_t	V_GLOBAL
fileWrite(void_p handle,void *buf,u32_t len)
{
	if(!libvIsHandle((void*)handle,"fileWrite",ioport_name,IOPORT_MAGIC))
		return 0;
	if(!buf || !len)
	{
#ifdef	CHECKED_BUILD
		conlPrintf(LOG_ERROR,
			"fileWrite(%X,%X,%d): incorrect source.\n",handle,buf,len);
#endif	/* CHECKED_BUILD */
		return 0;
	}
	return ((ioport_base_t*)handle)->write(handle,buf,len);
}

u32_t	V_GLOBAL
fileSeek(void_p handle,s32_t offset,int whence)
{
	if(!libvIsHandle((void*)handle,"fileSeek",ioport_name,IOPORT_MAGIC))
		return INVALID_IO_OFFSET;
	return ((ioport_base_t*)handle)->seek(handle,offset,whence);
}

u32_t	V_GLOBAL
fileTell(void_p handle)
{
	if(!libvIsHandle((void*)handle,"fileTell",ioport_name,IOPORT_MAGIC))
		return INVALID_IO_OFFSET;
	return ((ioport_base_t*)handle)->tell(handle);
}

u32_t	V_GLOBAL
fileSize(void_p handle)
{
	u32_t filepos,end;
	if(!libvIsHandle((void*)handle,"fileSize",ioport_name,IOPORT_MAGIC))
		return 0;
	filepos=((ioport_base_t*)handle)->tell((void*)handle);
    end=((ioport_base_t*)handle)->seek((void*)handle,0,SEEK_END);
    ((ioport_base_t*)handle)->seek(handle,filepos,SEEK_SET);
    return end;
}

vboolean	V_GLOBAL
fileClose(void_p handle)
{
	/* TODO: convert to use libvCloseHandle() */
	if(!libvIsHandle((void*)handle,"fileClose",ioport_name,IOPORT_MAGIC))
		return false;
	return ((ioport_base_t*)handle)->base.destroy(handle) == 0;
}

vboolean	V_GLOBAL
fileControl(void_p handle,u32_t code,void *parameters)
{
	int rc;
	if(!libvIsHandle((void*)handle,"fileControl",ioport_name,IOPORT_MAGIC))
		return false;
#ifdef	CHECKED_BUILD
	if(code>=pctl_max_code)
    	conlPrintf(LOG_WARNING,"fileControl(%u,%X) unknown code '%u'.\n",
        	code,parameters,code);
#endif	/* CHECKED_BUILD */
	rc=((ioport_base_t*)handle)->ioctl((void*)handle,code,parameters);
    if(rc==0)
    	return true;
#ifdef	CHECKED_BUILD
	else
    {
    	conlPrintf(LOG_ERROR,"file->ioctl(%d,%X) failed (rc %d).\n",
        	code,parameters,rc);
    }
#endif	/* CHECKED_BUILD */
	return false;
}
