#ifndef HV_FTP_H_
#define HV_FTP_H_

#ifdef __cplusplus
extern "C" {
#endif

#define FTP_COMMAND_PORT    21
#define FTP_DATA_PORT       20

// ftp_command
// X(name)
#define FTP_COMMAND_MAP(X) \
    X(HELP)     \
    X(USER)     \
    X(PASS)     \
    X(PWD)      \
    X(CWD)      \
    X(CDUP)     \
    X(MKD)      \
    X(RMD)      \
    X(STAT)     \
    X(SIZE)     \
    X(DELE)     \
    X(RNFR)     \
    X(RNTO)     \
    X(PORT)     \
    X(PASV)     \
    X(LIST)     \
    X(NLST)     \
    X(APPE)     \
    X(RETR)     \
    X(STOR)     \
    X(QUIT)     \

enum ftp_command {
#define X(name) FTP_##name,
    FTP_COMMAND_MAP(X)
#undef  X
};

// ftp_status
// XXX(code, name, string)
#define FTP_STATUS_MAP(XXX) \
    XXX(220,    READY,          Ready)  \
    XXX(221,    BYE,            Bye)    \
    XXX(226,    TRANSFER_COMPLETE,  Transfer complete)  \
    XXX(227,    PASV,           Entering Passive Mode)  \
    XXX(331,    PASS,           Password required)      \
    XXX(230,    LOGIN_OK,       Login OK)   \
    XXX(250,    OK,             OK)         \
    XXX(500,    BAD_SYNTAX,     Bad syntax)         \
    XXX(530,    NOT_LOGIN,      Not login)  \

enum ftp_status {
#define XXX(code, name, string) FTP_STATUS_##name = code,
    FTP_STATUS_MAP(XXX)
#undef  XXX
};

// more friendly macros
#define FTP_MKDIR       FTP_MKD
#define FTP_RMDIR       FTP_RMD
#define FTP_APPEND      FTP_APPE
#define FTP_REMOVE      FTP_DELE
#define FTP_DOWNLOAD    FTP_RETR
#define FTP_UPLOAD      FTP_STOR

#define FTP_RECV_BUFSIZE    8192

typedef struct ftp_handle_s {
    int     sockfd;
    char    recvbuf[FTP_RECV_BUFSIZE];
    void*   userdata;
} ftp_handle_t;

const char* ftp_command_str(enum ftp_command cmd);
const char* ftp_status_str(enum ftp_status status);

int ftp_connect(ftp_handle_t* hftp, const char* host, int port);
int ftp_login(ftp_handle_t* hftp, const char* username, const char* password);
int ftp_quit(ftp_handle_t* hftp);

int ftp_exec(ftp_handle_t* hftp, const char* cmd, const char* param);

// local => remote
int ftp_upload(ftp_handle_t* hftp, const char* local_filepath, const char* remote_filepath);
// remote => local
int ftp_download(ftp_handle_t* hftp, const char* remote_filepath, const char* local_filepath);

typedef int (*ftp_download_cb)(ftp_handle_t* hftp, char* buf, int len);
int ftp_download_with_cb(ftp_handle_t* hftp, const char* filepath, ftp_download_cb cb);

#ifdef __cplusplus
}
#endif

#endif // HV_FTP_H_
