/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


#ifndef	__FTPLIB__
#define __FTPLIB__


	#if __PLATFORM_WINDOWS__
		#include <winsock.h>
	#endif
		#include "ntypes.h"


/// FTP connection.
struct	FtpConnection
{
enum	Direction
{
	Upload				= 0,
	Download
};

		int				handle;
		bool			ready;

		char			*buffer;
		int				buffer_usage;

		Direction		direction;

		void			FreeBuffer();
		bool			AllocateBuffer();

		FtpConnection();
		~FtpConnection()
		{	FreeBuffer();	}
};

/*
	@short	FTP Library.
*/
class	FtpLibrary
{
public:

enum	ConnectionMode
{
	ConnectionPORT		= 0,
	ConnectionPASV
};

enum	TransferMode
{
	TransferASCII		=	'A',
	TransferBinary		=	'I'
};

enum	AccessType
{
	AccessDir			=	0,
	AccessDirVerbose,
	AccessFileRead,
	AccessFileWrite,
	AccessFileReadAppend,
	AccessFileWriteAppend
};

enum	State
{
	FtpError			=	0,
	FtpOk,
	FtpSocketTimeout
};

protected:

		char			response[256];

		FtpConnection	master_connection;
		ConnectionMode	connection_mode;

		size_t			offset;
		bool			correctpasv;

		/// Check server PASV support.
		bool			CheckPASVResponse(unsigned char *v);
		/// Read and verify a response from the server.
		bool			CheckResponse(char c);

		/// Wait for the socket to receive or flush data.
		State			WaitSocket(FtpConnection *socket);
		///	Read a line of text.
		State			ReadASCII(char *buf, int max, FtpConnection *socket, int &line_length);
		/// Write a line of text.
		State			WriteASCII(char *buf, int length, FtpConnection *socket, int &wrote_length);

		/// Send a command and wait for expected response.
		bool			FtpSendCmd(const char *cmd, char expresp);
		/// Accept connection from server.
		bool			FtpAcceptConnection(FtpConnection *connection);

		/// Create a PORT connection for data transfer.
		FtpConnection	*CreatePORTConnection(TransferMode mode, FtpConnection::Direction direction, char *connection_command);
		/// Create a PASV connection for data transfer.
		FtpConnection	*CreatePASVConnection(TransferMode mode, FtpConnection::Direction direction, char *connection_command);
		/// Create a connection for data transfer.
		FtpConnection	*CreateConnection(const char *path, AccessType type, TransferMode mode);
		/// Close connection.
		bool			CloseConnection(FtpConnection *connection);

		/// Generic data transfer function.
		State			DataTransfer(const char *local_path, const char *remote_path, AccessType type, TransferMode mode);
		/// Read data from a connection.
		State			ReadBinary(void *buffer, int max, FtpConnection *connection, int &length);
		/// Write data to a connection.
		State			WriteBinary(void *buffer, int length, FtpConnection *connection);

public:

		/// Set data connection transfer mode.
		void			SetDataConnectionMode(ConnectionMode mode)
		{	connection_mode = mode;	}

		/// Get last server response received.
		const char		*GetLastResponse() const
		{	return response;	}

		/// Connect to a remote server.
		bool			Connect(const char *host);
		/// Upload file to server.
		State			Upload(const char *local_path, const char *remote_path, TransferMode mode = TransferBinary, int offset = 0);
		/// Download file from server.
		State			Download(const char *local_path, const char *remote_path, TransferMode mode = TransferBinary, int offset = 0);
		/// Quit server, close connection.
		bool			Quit();

		/// Change directory.
		bool			ChangeDirectory(const char *path);
		/// Up directory.
		bool			UpDirectory();
		/// Delete remote file.
		bool			DeleteFile(const char *path);
		/// Get remote file size.
		int				GetFileSize(const char *path, TransferMode mode = TransferBinary);

		/// Download directory listing to a local file.
		bool			Nlst(const char *outputfile, const char *path);

		///	Login remote server.
		bool			Login(const char *user, const char *password);


/*
	Callback functions.
*/
virtual	bool		IdleCallback()
		{	return true;	}
virtual	void		SendCommandCallback(const char * /*command*/)
		{}
virtual	bool		DataReadCallback(const FtpConnection * /*connection*/)
		{	return true;	}
virtual	bool		DataWriteCallback(const FtpConnection * /*connection*/)
		{	return true;	}

		FtpLibrary();
virtual	~FtpLibrary();
};


#endif	// __FTPLIB__
