#include "BufferedFile.h"

extern int write(int fd,void * data, int size);

BufferedFile::BufferedFile(int fdesc)  {
	pushBackBlocks = vector<charAndSize *>();
	this->fd = fdesc;	
	timeToWait = 1000;
}
BufferedFile::~BufferedFile() {
	vector<charAndSize *>::iterator iter;
	for (iter = pushBackBlocks.begin(); iter < pushBackBlocks.end(); iter++) {
		delete (*iter);
	}
}

int BufferedFile::Write(const char * data,int size) {
	return write(fd,(const void *)data, size);
	//i = write(this->fd,(void *)data, sizeof(char)*size);
	//return (int)i;
}
void BufferedFile::pushBack(char * data,int size) {
	struct charAndSize * c = new charAndSize();
	c->data = data;
	c->size = size;
	c->alreadyRead = 0;
	pushBackBlocks.push_back(c);

}
int BufferedFile::Read(char * data, int size) {
	int index = 0;
	if (pushBackBlocks.size() > 0) {
		int si = 0;
		int sar = 0;
		int min = 0;
		int alr = 0;
		vector<charAndSize *>::iterator iter;
		for (iter = pushBackBlocks.begin(); iter < pushBackBlocks.end(); iter++) {
			si = size-index;
			min = si;
			alr = (*iter)->alreadyRead;
			sar = (*iter)->size - alr;
			if (sar < min) { sar = min; }
			for (int i = 0; i < min; i++) {
				data[index+i] =	(*iter)->data[alr+i];
			}
			if (sar > si) { //We haven't read enough of a block to count!
				(*iter)->alreadyRead+=si;
				return size;
			} else if ( sar == si ) { //We've read the entire block
				pushBackBlocks.erase(iter);
				delete (*iter);
				return size;
			} else { //We've read the entire block
				pushBackBlocks.erase(iter);
				delete (*iter);
				index+=min;
			}
		}
		if (index >= size) {
			return size;
		}
	}
	int total = read(fd,(void *)(data+index), sizeof(char)*(size-index));
	if (index) {
		return total + index;
	} else {
		return total;
	}
}
bool BufferedFile::readReady() {return ready(0);}
bool BufferedFile::writeReady() {return ready(1);}

void BufferedFile::Close() {
	close(fd);
}

bool BufferedFile::ready(int rw) {
	if (pushBackBlocks.size() > 0) {
		return true;
	}
	fd_set tmp_set;
	FD_ZERO (&tmp_set);
	FD_SET (fd, &tmp_set);
	struct timeval tv;
	tv.tv_sec = 0;
	tv.tv_usec = timeToWait; 
	int currCount;
	if (!rw) {
		currCount = select(fd+1, &tmp_set, NULL, NULL, &tv);
	} else {
		currCount = select(fd+1 ,NULL, &tmp_set,  NULL, &tv);
	}
	return (currCount > 0);
}
void BufferedFile::setWait(int w) {
	timeToWait = w;
}
int BufferedFile::getWait() {
	return timeToWait;
}

