/*
 * Copyright (c) 2009-2017 Satlab Aps <satlab@satlab.com>
 * All rights reserved. Do not distribute without permission.
 */

#ifndef _SL_BTP_CLIENT_H_
#define _SL_BTP_CLIENT_H_

#include <stdint.h>
#include <stdbool.h>

#include <csp/csp.h>

#include <btp/types.h>

/**
 * Magic offset value to indicate next available block in
 * btp_client_get_blocks/btp_client_send_blocks offset argument.  
 */
#define BTP_OFFSET_NEXT	(UINT32_MAX)

/** BTP context struct */
struct btp_context {
	uint8_t host;
	uint8_t port;
	bool connected;
	bool complete;
	bool paranoid;
	bool raw;
	enum btp_xfer_state state;
	csp_conn_t *conn;
	int fd;
	int fd_map;
	char filename[BLOB_NAME_SIZE];
	char mapname[BLOB_NAME_SIZE + 4];
	uint32_t blocks;
	uint32_t block_size;
	uint32_t size;
	uint32_t progress;
	uint32_t checksum;
	uint32_t next;
	uint32_t bits;
	uint8_t *block_status;
};

/**
 * @brief Progress callback function
 *
 * This function is repeatedly called by the BTP stack when transferring data,
 * and can be used to show the transfer progress.
 *
 * @param ctx BTP context
 * @param arg Pointer value passed through btp_client_get_blocks/send_blocks.
 */
typedef void (*progress_cb)(struct btp_context *ctx, void *arg);

/**
 * @brief Open new BTP connection to host
 *
 * @param host CSP host to connect to
 * @param port CSP port on host with BTP server
 * @param timeout Timeout in milliseconds
 * @param opts Extra CSP connection options
 *
 * @return A btp_context object on success, NULL on failure
 */
struct btp_context *btp_client_connect(uint8_t host, uint8_t port,
				       uint32_t timeout, uint32_t opts);

/**
 * @brief Close an active BTP connection
 *
 * @param ctx An open btp_context
 *
 * @return 0 on success, error code on failure
 */
int btp_client_disconnect(struct btp_context *ctx);

/**
 * @brief Begin upload of a file
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param backend Backend to upload to
 * @param filename Absolute path where file should be uploaded
 * @param localfile Absolute path to the file to upload
 * @param block_size Number of bytes to upload per block
 * @param offset If nonzero, skip the first offset bytes in localfile
 * @param size If nonzero, only upload size bytes
 * @param timeout Timeout in milliseconds
 * @param force If true, force upload even if transfer is already complete
 * @param paranoid If true, sync blocks to disk after each block transfer
 *
 * @return 0 on success, error code on failure
 */
int btp_client_upload(struct btp_context *ctx, char *backend, char *filename,
		      char *localfile, uint8_t block_size, uint32_t offset,
		      uint32_t size, uint32_t timeout, bool force, bool paranoid);

/**
 * @brief Begin download of a file
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param backend Backend to download from
 * @param filename Absolute path to remote file to download
 * @param localfile Absolute path where downloaded file should be stored
 * @param block_size Number of bytes to download per block
 * @param offset If nonzero, skip the first download bytes in filename
 * @param size If nonzero, only download size bytes
 * @param timeout Timeout in milliseconds
 * @param force If true, force download even if transfer is already complete
 * @param paranoid If true, sync blocks to disk after each block transfer
 *
 * @return 0 on success, error code on failure
 */
int btp_client_download(struct btp_context *ctx, char *backend, char *filename,
			char *localfile, uint8_t block_size, uint32_t offset,
			uint32_t size, uint32_t timeout, bool force, bool paranoid);

/**
 * @brief Update upload status
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param timeout Timeout in milliseconds
 *
 * @return 0 on success, error code on failure
 */
int btp_client_request_status(struct btp_context *ctx, uint32_t timeout);

/**
 * @brief Send download status
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param timeout Timeout in milliseconds
 *
 * @return 0 on success, error code on failure
 */
int btp_client_send_status(struct btp_context *ctx, uint32_t timeout);

/**
 * @brief Request blocks in download
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param offset Start from block offset
 * @param count Number of blocks to download
 * @param timeout Timeout in milliseconds
 * @param cb Progress callback function
 * @param cbarg Argument passed to callback
 *
 * @return 0 on success, error code on failure
 */
int btp_client_get_blocks(struct btp_context *ctx, unsigned int offset,
			  unsigned int count, uint32_t timeout, progress_cb cb,
			  void *cbarg);

/**
 * @brief Send blocks in upload
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param offset Start from block offset
 * @param count Number of blocks to upload
 * @param timeout Timeout in milliseconds
 * @param cb Progress callback function
 * @param cbarg Argument passed to callback
 *
 * @return 0 on success, error code on failure
 */
int btp_client_send_blocks(struct btp_context *ctx, unsigned int offset,
			   unsigned int count, uint32_t timeout, progress_cb cb,
			   void *cbarg);

/**
 * @brief Finish active transfer
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param timeout Timeout in milliseconds
 *
 * @return 0 on success, error code on failure
 */
int btp_client_complete(struct btp_context *ctx, uint32_t timeout);

/**
 * @brief Test is tranfer is finished
 *
 * @param ctx An open btp_context from btp_client_connect
 *
 * @return true if transfer is complete, false otherwise
 */
bool btp_client_finished(struct btp_context *ctx);

/**
 * @brief Remove file
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param backend Backend to remove file on
 * @param path Absolute path to remote file to remove
 * @param timeout Timeout in milliseconds
 *
 * @return 0 on success, error code on failure
 */
int btp_client_remove(struct btp_context *ctx, char *backend,
		      char *path, uint32_t timeout);

/**
 * @brief Move file
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param backend Backend to move file on
 * @param frompath Absolute path to file to move
 * @param topath Absolute path where file should be moved
 * @param timeout Timeout in milliseconds
 *
 * @return 0 on success, error code on failure
 */
int btp_client_move(struct btp_context *ctx, char *backend,
		    char *frompath, char *topath, uint32_t timeout);

/**
 * @brief Copy file
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param backend Backend to copy file on
 * @param frompath Absolute path to file to copy
 * @param topath Absolute path where file should be copied
 * @param timeout Timeout in milliseconds
 *
 * @return 0 on success, error code on failure
 */
int btp_client_copy(struct btp_context *ctx, char *backend,
		    char *frompath, char *topath, uint32_t timeout);

/**
 * @brief List files
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param count Maximum number of files to list
 * @param backend Backend to list files on
 * @param name Absolute path to list
 * @param timeout Timeout in milliseconds
 *
 * @return 0 on success, error code on failure
 */
int btp_client_list(struct btp_context *ctx, uint16_t count,
		    char *backend, char *name, uint32_t timeout);

/**
 * @brief Create shell connection
 *
 * @param ctx An open btp_context from btp_client_connect
 * @param count Maximum number of reply packets
 * @param cmd Command to execute. Use cmd[0] = '\0' for interactive mode
 * @param raw If true, transmit one packet per character
 * @param timeout Timeout in milliseconds
 *
 * @return 0 on success, error code on failure
 */
int btp_client_shell(struct btp_context *ctx, uint16_t count,
		     char *cmd, bool raw, uint32_t timeout);

#endif /* _BTP_CLIENT_H_ */
