#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>

#include "sftp.h"

extern sftp_channel *channel[MAXCHANNEL];

#define WAITING_FOR_NAME 0
#define WAITING_FOR_SIZE 1
#define WAITING_FOR_ATTR 2
#define RECEIVING 3
#define DONE 4

static int sock = 1;

typedef struct {
	char *name;
	int fd, size, count, state;
	u_int16_t mode;
} recvfile_data;

int recvfile_accept_data(sftp_channel_t c, message m);
int recvfile_send_data(sftp_channel_t c);

sftp_channel_t
new_recvfile_channel(sftp_channel_t c) {
	channel[c] = new_channel();
	channel[c]->accept_data = recvfile_accept_data;
	channel[c]->send_data = recvfile_send_data;
	channel[c]->data = malloc(sizeof(recvfile_data));
	memset (channel[c]->data, 0, sizeof(recvfile_data));
	return c;
}

int
recvfile_accept_data(sftp_channel_t c, message m) {
	recvfile_data *data = channel[c]->data;
	switch (m.command) {
		case FILENAME:
			if (data->state == WAITING_FOR_NAME) {
				u_int8_t status;

				data->name = strdup(m.data);
				data->fd = open(data->name, O_WRONLY|O_CREAT);
				status = (data->fd >= 0);
				send_message(sock, _data_message(c, FILEOK,
								 &status, 1));
				if (status == 0)
					return -1;
				fchmod(data->fd, 0664);
				data->state = WAITING_FOR_SIZE;
			}
			else
				return -1;
			break;
		case FILESIZE:
			if (data->state == WAITING_FOR_SIZE) {
				data->size = ntohl(*(u_int32_t *)m.data);
				data->state = WAITING_FOR_ATTR;
			}
			else
				return -1;
			break;
		case FILEMODE:
			if (data->state == WAITING_FOR_ATTR) {
				if (m.len != 9)
					return -1;
				data->mode = strtomode(m.data);
				fchmod(data->fd, data->mode);
				data->state = RECEIVING;
			}
			else
				return -1;
			break;
		case DATA:
			if (data->state == WAITING_FOR_ATTR)
				data->state = RECEIVING;
			if (data->state == RECEIVING) {
				write(data->fd, m.data, m.len);
				data->count += m.len;
			}
			else
				return -1;
			if (data->count >= data->size)
				data->state = DONE;
			break;
		case ENDDATA:
			if (data->state == DONE)
				close(data->fd);
			else
				return -1;
			break;
		case ERROR:
			return -1;
		default:
			return -1;
	}
	return 0;
}

int
recvfile_send_data(sftp_channel_t c) {
	return 0;
}

void
close_recvfile_channel(sftp_channel_t c) {
	recvfile_data *data = channel[c]->data;
	free(data->name);
	free(data);
	free(channel[c]);
	channel[c] = NULL;
}
