#ifndef __XFer__H
#define __XFer__H

#include <stdarg.h>
#include <stdio.h>

#include "kernel.h"

#include <stdbool.h>
#include "WimpLib:Coords.h"
#include "WimpLib:Event.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct XFer XFer;

#define XFer_NoTransfer (const _kernel_oserror*) 1
extern const _kernel_oserror XFer_Error_EOF;

/* ------------------------ XFer_SetSaveType -------------------------------
 * Description: A function of this type should examine the given list
 *              of file types and return the first supported one
 *              or the native file type.
 *
 * Parameters:  handle          handle of data to save
 *              types           list of file types
 *
 * Returns:     Return the first supported file type
 *              or the native file type.
 *
 * Other Info:  None.
 *
 */

typedef file_type (*XFer_SetSaveType)(void* handle, const file_type* types);

/* ----------------------- XFer_SendProc ------------------------------------
 * Description: A function of this type is called by XFer_Send
 *              to request the next chunk of data to send
 *              to the file or the memory pipe.
 *
 * Parameters:  handle          handle which was passed to XFer_Send()
 *              type            type of the file to be writtten
 *              sXFer_Chunck    ref is the number of the chunk requested,
 *                              or 0 for the first chunk
 *
 * Returns:     The function must fill the address and size of
 *              the chunck of data to send and the ref of the next chunk.
 *              This ref does not need to be old ref + 1 it can be anything
 *              but zero (which is always the ref when you are asked for
 *              the first chunk of data).
 *              Returning false signals to XFer_Send that there are no
 *              more chuncks of data to send.
 *
 * Other Info:  None.
 *
 */

typedef struct
{
	int         ref;
	const char* pdata;
	int         size;
	const char* filename;
} sXFer_Chunk;

typedef bool (*XFer_SendProc)(void* handle, file_type type, sXFer_Chunk* pchunk);

/* ----------------------- XFer_RemoveProc ----------------------------------
 * Description: A function of this type is called by XFer_Send
 *              when transfer is completed correctly and request
 *              was made to delete the source data.
 *
 * Parameters:  handle          handle which was passed to XFer_Send()
 *
 * Returns:     Nothing.
 *
 * Other Info:  None.
 *
 */

typedef void (*XFer_RemoveProc)(void* handle);

/* ----------------------- XFer_OnSafeProc ----------------------------------
 * Description: A function of this type will be called when
 *              the transfer occured to a safe destination.
 *              Use it to set the new filename of a document
 *              and to mark the document as unmodified.
 *
 * Parameters:  filename        name under which the document was saved.
 *
 * Returns:     Nothing.
 *
 * Other Info:  None.
 *
 */

typedef void (*XFer_OnSafeProc)(void* handle, const char* filename);

/* --------------------------- XFer_PrintProc -------------------------------
 * Description: A function of this type should either print the file
 *              directly, or save it into the given filename, from
 *              where it will be printed by the printer application.
 *
 * Parameters:  handle          handle that was passed to DragDrop_Send()
 *              filename        name of file to save into, for printing
 *              type            type to give to saved file
 *
 * Returns:     The function should return either the file type of the
 *              file it saved, or one of the reason codes #defined below.
 *
 * Other Info:  This is called if the file icon has been dragged onto a
 *              printer application.
 *
 */

#define XFer_printPrinted -1    // file dealt with internally
#define XFer_printFailed  -2    // had an error along the way

typedef int (*XFer_PrintProc)(void* handle, char* filename, file_type type);

/* --------------------------- XFer_OnErrorProc -----------------------------
 * Description: A function of this type is called by XFer_Send to report
 *              any error occuring during the transfer process.
 *
 * Parameters:  err             error to report
 *
 * Returns:     The error (for compatibility of Task_ReportOSError).
 *
 * Other Info:  None.
 *
 */

typedef const _kernel_oserror* (*XFer_OnErrorProc)(const _kernel_oserror* err);

/* ----------------------- XFer_ReceiveProc ------------------------------------
 * Description: A function of this type should call XFer_ReceiveRead
 *              to read its data from the file or the memory pipe
 *              controlled by the XFER handle.
 *
 * Parameters:  handle          handle which was passed to XFer_Receive()
 *              xfer            XFER handle of current transfer
 *              type            file type of received data
 *              pPos            screen info about were the file was dropped
 *                              (icon can contain an internal handle set
 *                              by your DragDrop and Clipboard handlers)
 *                              or NULL if load not issued from drag & drop
 *
 * Returns:     The function must return NULL if data was successfully
 *              read, else the error that occured.
 *
 * Other Info:  none.
 *
 */

typedef const _kernel_oserror* (*XFer_ReceiveProc)(void* handle, XFer* xfer, file_type type, const ScreenPos* pPos);

/*= Public interface ==========================================================*/

/* ----------------------------- XFer_Send ---------------------------------------
 * Description: Allows the user to export application data to a file
 *              or to another application.
 *              Used after icon drag (and drop) or by clipboard.
 *
 * Parameters:  msg_ref         message ref to reply to, (0 if none)
 *              task            task to send to, (0 to broadcast if no msg_ref)
 *              w               window to send to
 *              i               icon handle (or internal handle, cf clipboard)
 *              x, y            mouse position on screen
 *              estsize         estimated size of the file
 *                              -1 if tranfser is not safe
 *              type            file type of data
 *              filename        suggested file name
 *              FNSendProc      caller-supplied function for providing
 *                              application data chunks during the
 *                              data transfer
 *              FNRemoveProc    caller-supplied function to delete source
 *                              data when transfer is completed
 *                              or 0 if source data must remain intact
 *              FNOnSafeProc    caller-supplied function for updating
 *                              application data modif status and
 *                              filename if it was a safe transfer to a file
 *                              or 0 (i.e. when saving a selection)
 *              FNPrintProc     caller-supplied function for printing
 *                              application data, if "icon" is
 *                              dragged onto printer application
 *                              ! not supported yet !
 *              FNOnErrorProc   caller-supplied function for reporting
 *                              errors occurring during the transfer
 *              handle          handle to be passed to handler functions.
 *
 * Returns:     true if transfer completed correctly
 *
 * Other Info:  You should typically call this function in a window's
 *              event handler, when you get a "mouse drag" event.
 *              XFer_Send deals with the complexities of message-passing
 *              protocols to achieve the data transfer. Refer to the above
 *              typedefs for an explanation of what the
 *              caller-supplied functions should do.
 *              If you pass 0 as the XFer_PrintProc, then the file
 *              format for printing is assumed to be the same as for saving
 *              The estimated file size is not essential, but may improve
 *              performance.
 *
 */

bool XFer_Send(unsigned int msg_ref
		, HTask task
		, HWind w
		, HIcon i
		, int x
		, int y
		, int estsize
		, file_type type
		, const char* filename
		, XFer_SendProc FNSend
		, XFer_RemoveProc FNRemove
		, XFer_OnSafeProc FNOnSafe
		, XFer_PrintProc FNPrint
		, XFer_OnErrorProc FNOnError
		, bool asfileonly
		, void* handle);

/* ----------------------------- XFer_SendToFile ---------------------------------
 * Description: Allows the user to export application data to a file.
 *              Used after clicking on the save button of your document
 *              or on OK button in the save box. See XFer_Send for details.
 *
 * Parameters:  filename        suggested file name
 *              type            file type of data
 *              FNSendProc      caller-supplied function for providing
 *                              application data chunks during the
 *                              data transfer
 *              FNOnSafeProc    caller-supplied function for updating
 *                              application data modif status and
 *                              filename if it was a safe transfer to a file
 *                              or 0 (i.e. when saving a selection)
 *              handle          handle to be passed to handler functions.
 *
 * Returns:     0 if performed successfully or the error that occured.
 *
 * Other Info:  None.
 *
 */


const _kernel_oserror* XFer_SendToFile( const char* filename
				, file_type type
				, XFer_SendProc FNSend
				, XFer_OnSafeProc FNOnSafe
				, void* handle);


/* ----------------------------- XFer_Receive ------------------------------------
 * Description: Allows the user to import data from a file or another application.
 *              Used after icon drag (and drop) or by clipboard.
 *
 * Parameters:  rcv             the message asking to load data
 *              FNReceive       caller-supplied function for reading the data
 *              handle          handle to be passed to handler functions.
 *
 * Returns:     The possible error occuring during the loading of the data
 *              (reading error, out of memory errors, ...), 0 if the transfer
 *              was succesfull or XFer_NoTransfer if no data was loaded.
 *
 * Other Info:  You should typically call this function in a window's
 *              event handler, when you get a Message_DataLoad or Message_DataSave
 *              message. XFer_Receive deals with the complexities of message-passing
 *              protocols to achieve the data transfer.
 *              A normal file loading procedure is composed of one fopen(), multiple
 *              fread()s and one fclose(). In the XFer_ReceiveProc, you suppress
 *              the fopen() and fclose() and replace the fread()s by
 *              XFer_ReceiveRead()s.
 *
 */

const _kernel_oserror* XFer_Receive(const Msg* rcv
				, XFer_ReceiveProc FNreceive
				, void* handle);

/* ----------------------------- XFer_ReceiveFromFile ----------------------------
 * Description: Allows the user to import data from a file.
 *              Used for loading files given at the command line or default files.
 *              Also called by XFer_Receive.
 *
 * Parameters:  filename        the name of the file to load
 *              FNReceive       caller-supplied function for reading the data
 *              handle          handle to be passed to handler functions.
 *              pPos            0 in general but allows to simulate
 *                              dropping a file in a window
 *
 * Returns:     The possible error occuring during the loading of the data
 *              (reading error, out of memory errors, ...), NULL if the transfer
 *              was succesfull or XFer_NoTransfer if no data was loaded.
 *
 * Other Info:  See XFer_Receive for details.
 */

const _kernel_oserror* XFer_ReceiveFromFile(    const char* filename
					, XFer_ReceiveProc FNreceive
					, void* handle
					, const ScreenPos* pPos);

/* Use in Receive callback to read n bytes of data */
int XFer_ReceiveRead(XFer* xfer, void* pdata, int size);
const _kernel_oserror* XFer_GetErrorStatus(const XFer* xfer);
int XFer_GetEstimatedTotalSize(const XFer* xfer);
int XFer_CountReceived(const XFer* xfer);

#ifdef __cplusplus
}
#endif

#endif
