#include "Connector.h"
/**
 * The default port to connect to start at.
 */
#define DEFAULT_PORT 6780

Connector::Connector() {
	init(DEFAULT_PORT,DEFAULT_PORT+1,DEFAULT_PORT+2,DEFAULT_PORT+3);
}
Connector::~Connector() {
	list<ConnectionWrap *>::iterator iter;
	for (iter = allConnections->begin(); iter != allConnections->end(); iter++) {
		(*iter)->disconnect();
		delete *iter;
	}
	allConnections->clear();
	
	list<ConfigConnection *>::iterator citer;
	for (citer = configConnections->begin(); citer != configConnections->end(); citer++) {
		(*citer)->disconnect();
		delete *citer;
	}
	configConnections->clear();
	currentConfig = NULL;
	{
		list<ConnectionWrap *>::iterator iter;
		for (iter = allConnections->begin(); iter != allConnections->end(); iter++) {
			allConnections->erase(iter);
			delete (*iter);
		}
	}
	{
		list<ConfigConnection *>::iterator iter;
		for (iter = configConnections->begin(); iter != configConnections->end(); iter++) {
			configConnections->erase(iter);
			delete (*iter);
		}
	}
	delete allConnections;
	delete configConnections;
	delete (MessageExecutor*)messageExecutor;
	delete connectionFactory;
	delete bf;
}
Connector::Connector(int start) {
	init(start,start+1,start+2,start+3);
}
Connector::Connector(int inputport,int outputport,int filterport, int configport) {
	init(inputport,outputport,filterport,configport);
}
void Connector::init(int inputport,int outputport,int filterport, int configport) {
	bf = new BufferedFileFactory();
	connectionFactory = new ConnectionFactory(bf,inputport,outputport,filterport,configport);
	updated();
	allConnections = new list<ConnectionWrap *>();
	messageExecutor = new MessageExecutor();
	configConnections = new list<ConfigConnection *>();
	ConnectorSingleton().setConnector(this);
	quit = false;
	processUpdate = lastUpdated;
}
int Connector::lastUpdate() {
	return lastUpdated;
}
void Connector::lastChange() {
	char number[12];
	snprintf(number,12,"%d",lastUpdate());
	string final = "<lastChange>";
	final += "<time>";
	final += string(number);
	final += "</time></lastChange>";
	currentConfig->write(final.c_str(),final.size());
}
void Connector::updated() {
	lastUpdated = time(NULL);
}
list<ConnectionWrap *> * Connector::getConnectionList() {
	return allConnections;
}
void Connector::disconnect(int fd) {
	list<ConnectionWrap *>::iterator eter;
	list<ConnectionWrap *>::iterator iter;
	ConnectionWrap * it = NULL;
	int fh;
	for (eter = allConnections->begin(); eter != allConnections->end(); eter++) {
		
		fh = (*eter)->getFileHandle();
		if (fd == fh) {
			it = *eter;
			break;
		}
	}
	if (it!=NULL) {
		allConnections->remove(it);
		for (iter = allConnections->begin(); iter != allConnections->end(); iter++) {
			(*iter)->disconnectFrom(it);
		}
		it->disconnect();
		updated();
		delete it;
		return;
	}
	//ERROR
	throw new string("No connection found. Could not disconnect connection");
}
void Connector::unPatch(int from, int to) {
	cout << "UNPATCH " << from << " TO " << to << "\n";
	list<ConnectionWrap *>::iterator iter;
	ConnectionWrap * fromConn = NULL;
	ConnectionWrap * toConn = NULL;
	for (iter = allConnections->begin(); iter != allConnections->end(); iter++) {
		int fd = (*iter)->getFileHandle();
		if (fd == from) {
			fromConn = (*iter);
		} else if (fd == to) {
			toConn = (*iter);
		}
	}
	if (fromConn == NULL || toConn == NULL) {
		throw new string("There is no patch between these connections!");
	}
	toConn->disconnectFrom(fromConn);
	updated();
}
void Connector::patch(int from, int to) {
	list<ConnectionWrap *>::iterator iter;
	ConnectionWrap * fromConn = NULL;
	ConnectionWrap * toConn = NULL;
	for (iter = allConnections->begin(); iter != allConnections->end(); iter++) {
		int fd = (*iter)->getFileHandle();
		if (fd == from) {
			fromConn = (*iter);
			if (toConn!=NULL) { break;}

		} else if (fd == to) {
			toConn = (*iter);
			if (fromConn!=NULL) { break;}
		} 
	}
	if (fromConn == NULL || toConn == NULL) {
		throw new string("There is no patch between these connections!");
	}
	if (!fromConn->readable()) {
		throw new string("This is not a valid patch!");
	}
	toConn->connectFrom(fromConn);
	updated();
}
void Connector::sendUpdate() {
	char number[12];
	if (currentConfig==NULL) {
		list<ConfigConnection *>::iterator iter;
		for (iter = configConnections->begin(); iter != configConnections->end(); iter++) {
			currentConfig = (*iter);
			break;
		}
		if (currentConfig==NULL) {
			return; //No ConfigConnections
		}
	}
	string final = "<update>";
	list<ConnectionWrap *>::iterator iter;
	for (iter = allConnections->begin(); iter != allConnections->end(); iter++) {
		string * str = (*iter)->getXML();
		if (str!=NULL) {
			final += *str;
			delete str;
		}
	}
	snprintf(number,12,"%d",lastUpdate());
	final += "<time>";
	final += string(number);
	final += "</time></update>";
	currentConfig->write(final.c_str(),final.size());
}

int percycle = 1000000/(44100/BUFFSIZE);
void Connector::process() {
	//Call process on data connections
	//Check config connections
	//Check for new connections
	//struct timeval tv;
	//struct timezone tz;
	//gettimeofday(&tv,&tz);
	//long milli =  tv.tv_usec;
	//int rw = bf->process(100);
	int rw = bf->process(percycle);
	Clock::clock++;
	if (rw) {
		list<ConnectionWrap *>::iterator iter;
		for (iter = allConnections->begin(); iter != allConnections->end(); iter++) {
			if ((*iter)->isClosed()) {
				disconnect((*iter)->getFileHandle());
				updated();
			} else {
				(*iter)->process();
			}
		}
		list<ConfigConnection *>::iterator citer;
		if (processUpdate!=lastUpdated) {
			ConfigConnection * tmp = currentConfig;
			for (citer = configConnections->begin(); citer != configConnections->end(); citer++) {
				currentConfig = *citer;
				try {
					sendUpdate();
				} catch (string * err) {
					cout << "Disconnecting a ConfigConnection\n";
					configConnections->remove(currentConfig);
					//delete *citer;
					delete  currentConfig;
					currentConfig = NULL;
					delete err;
				}
			}
			processUpdate = lastUpdated;
			currentConfig = tmp;
		}
		for (citer = configConnections->begin(); citer != configConnections->end(); citer++) {
			try {
				if ((*citer)->isMessage()) {
					currentConfig = (*citer);
					Message *m = (*citer)->getMessage();
					string * mstr = m->getXML();
					cout << "THERE IS A MESSAGE "<< *mstr << "\n" ;
					try {
						((MessageExecutor*)messageExecutor)->executeMessage(m);
					} catch (string * err) {
						string error = "<error>";
						error += *err;
						error += "</error>";
						currentConfig->write(error.c_str(),error.size());
					}
					delete m;
				} 
				if (processUpdate!=lastUpdated) {
					
				}
			} catch (string * err) {
				cout << "Disconnecting a ConfigConnection\n";
				configConnections->remove(currentConfig);
				//delete *citer;
				delete  currentConfig;
				currentConfig = NULL;
				delete err;
				break;
			}       	
		}        
	}
	if (connectionFactory->isThereANewConnection()) {
		cout << "There is a connection!\n";
	
		ConnectionWrap * wrap = connectionFactory->processConnection();
		if (wrap!=NULL) {
			cout << (int)(wrap->conn.floatConn->getFileHandle()) << "\n";
			assert(wrap->conn.floatConn!=0);
			if (wrap->type == CONFIGCONN) {
				cout << "It's a config connection!\n";
				configConnections->push_back(wrap->conn.configConn);
				wrap->conn.configConn = NULL;
				delete wrap;
			} else if (wrap == NULL) {
				cout << "NULL Wrapper Returned?\n";
			} else {
				cout << "It's not config connection!\n";
				allConnections->push_back(wrap);
			} 
			updated();
		} else {
			cout << "Connection Failed!\n";
		}
	}
	//usleep(percycle/2);
	//gettimeofday(&tv,&tz);
	//long remainder = percycle - (tv.tv_usec - milli);
	//if (remainder > 0) { 
	//	usleep(remainder);
	//}
}
void Connector::shutDown() {
	quit = true;

}
bool Connector::done() { 
	return quit;
}
