static int websocket_callback(struct libwebsocket_context *context,struct libwebsocket *wsi,enum libwebsocket_callback_reasons reason, void *user,void *in, size_t len)
{
	//printf("Switch: %i\n",reason);


	switch (reason)
	{
		case LWS_CALLBACK_CLIENT_WRITEABLE:
		{
			//Connection has been established.
			//printf("Connection established\n");
			break;
		}
		case LWS_CALLBACK_CLOSED:
		{
			//Connection is closed, we need to remove all related sinks
			sinkManager->disconnectAll(wsi);
			/*g_io_
			GIOChannel *chan = g_io_channel_unix_new((int)(long)user);
			g_io_add_watch(chan,G_IO_IN,(GIOFunc)gioPollingFunc,0);
			g_io_add_watch(chan,G_IO_PRI,(GIOFunc)gioPollingFunc,0);
			pollfds[count_pollfds].fd = (int)(long)user;
			pollfds[count_pollfds].events = (int)len;
// 			pollfds[count_pollfds++].revents = 0;*/
			break;
		}
		case LWS_CALLBACK_CLIENT_RECEIVE:
		{
			//printf("Client writable\n");
			break;
		}
		case LWS_CALLBACK_SERVER_WRITEABLE:
		{
			//printf("Server writable\n");
			break;
		}

		case LWS_CALLBACK_RECEIVE:
		{
			//printf("Data Received: %s\n",(char*)in);
			//The lack of a break; here is intentional.
		}
		case LWS_CALLBACK_HTTP:
		{
			//TODO: Verify that ALL requests get sent via LWS_CALLBACK_HTTP, so we can use that instead of LWS_CALLBACK_RECIEVE
			//TODO: Do we want exceptions, or just to return an invalid json reply? Probably an invalid json reply.
			DebugOut() << __SMALLFILE__ << ":" << __LINE__ << " Requested: " << (char*)in << "\n";
			GError* error = nullptr;


			JsonParser* parser = json_parser_new();
			if (!json_parser_load_from_data(parser,(char*)in,len,&error))
			{
				DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error loading JSON\n";
				return 0;
			}

			JsonNode* node = json_parser_get_root(parser);
			if(node == nullptr)
			{
				DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error getting root node of json\n";
				//throw std::runtime_error("Unable to get JSON root object");
				return 0;
			}

			JsonReader* reader = json_reader_new(node);
			if(reader == nullptr)
			{
				DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "json_reader is null!\n";
				//throw std::runtime_error("Unable to create JSON reader");
				return 0;
			}





			string type;
			json_reader_read_member(reader,"type");
			type = json_reader_get_string_value(reader);
			json_reader_end_member(reader);

			string  name;
			json_reader_read_member(reader,"name");
			name = json_reader_get_string_value(reader);
			json_reader_end_member(reader);
			
			string id;
			json_reader_read_member(reader,"transactionid");
			if (strcmp("gchararray",g_type_name(json_node_get_value_type(json_reader_get_value(reader)))) == 0)
			{
				//Type is a string
				id = json_reader_get_string_value(reader);
			}
			else
			{
				//Type is an integer
				stringstream strstr;
				strstr << json_reader_get_int_value(reader);
				id = strstr.str();
			}
			json_reader_end_member(reader);

			
			if (type == "method" && name == "getRanged")
			{
				json_reader_read_member(reader,"data");
				if (json_reader_is_object(reader))
				{
					double timeBegin;
					double timeEnd;
					double sequenceBegin;
					double sequenceEnd;
					string property;
					if (json_reader_read_member(reader,"timeBegin"))
					{
						timeBegin = boost::lexical_cast<double,std::string>(json_reader_get_string_value(reader));
						json_reader_end_member(reader);
					}
					
					if (json_reader_read_member(reader,"timeEnd"))
					{
						timeEnd = boost::lexical_cast<double,std::string>(json_reader_get_string_value(reader));
						json_reader_end_member(reader);
					}
					if (json_reader_read_member(reader,"sequenceBegin"))
					{
						sequenceBegin = boost::lexical_cast<double,std::string>(json_reader_get_string_value(reader));
						json_reader_end_member(reader);
					}
					if (json_reader_read_member(reader,"sequenceEnd"))
					{
						sequenceEnd = boost::lexical_cast<double,std::string>(json_reader_get_string_value(reader));
						json_reader_end_member(reader);
					}
					if (json_reader_read_member(reader,"property"))
					{
						property = json_reader_get_string_value(reader);
						json_reader_end_member(reader);
					}
					if ((timeBegin < 0 && timeEnd > 0) || (timeBegin > 0 && timeEnd < 0))
					{
						//Invalid time begin/end pair
					}
					if ((sequenceBegin < 0 && sequenceEnd > 0) || (sequenceBegin > 0 && sequenceEnd < 0))
					{
						//Invalid sequence begin/end pair
					}
					sinkManager->addSingleShotRangedSink(wsi,property,timeBegin,timeEnd,sequenceBegin,sequenceEnd,id);
				}
				json_reader_end_member(reader);
			}
			else
			{

				vector<string> data;
				list<string> key;
				list<string> value;
				json_reader_read_member(reader,"data");
				if (json_reader_is_array(reader))
				{
					for(int i=0; i < json_reader_count_elements(reader); i++)
					{
						json_reader_read_element(reader,i);
						if (json_reader_is_value(reader))
						{
							//Raw string value
							string path = json_reader_get_string_value(reader);
							data.push_back(path);

						}
						else
						{
							//Not a raw string value, then it's "property/value" kvp, for "set" requests
							json_reader_read_member(reader,"property");
							string keystr = json_reader_get_string_value(reader);
							key.push_back(keystr);
							json_reader_end_member(reader);
							json_reader_read_member(reader,"value");
							string valuestr = json_reader_get_string_value(reader);
							value.push_back(valuestr);
							json_reader_end_member(reader);
						}
						json_reader_end_element(reader);
					}
				}
				else
				{
					string path = json_reader_get_string_value(reader);
					if (path != "")
					{
						data.push_back(path);
					}
				}
				json_reader_end_member(reader);
				if (type == "method")
				{
					if (name == "get")
					{
						if (data.size() > 0)
						{
							//GetProperty is going to be a singleshot sink.
							//string arg = arguments.front();
							sinkManager->addSingleShotSink(wsi,data.front(),id);
						}
						else
						{
							DebugOut() << __SMALLFILE__ << ":" << __LINE__ << " \"get\" method called with no data! Transaction ID:" << id << "\n";
						}
					}
					else if (name == "set")
					{
						if (data.size() > 0)
						{
						  //Should not happen
						}
						else if (value.size() > 0)
						{
							if (key.size() != value.size())
							{
								DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "\"set\" method called with an invalid key value pair count\n";
							}
							else
							{
								list<string>::iterator d = value.begin();
								for (list<string>::iterator i=key.begin();i!=key.end();i++)
								{
									DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "websocketsinkmanager setting" << (*i) << "to" << (*d) << "\n";
									//(*i);
									sinkManager->setValue((*i),(*d));
									//(*d);
									d++;
								}

							}
						}
					}
					else if (name == "subscribe")
					{
						//Websocket wants to subscribe to an event, data.front();
						for (auto i=data.begin();i!=data.end();i++)
						{
							sinkManager->addSink(wsi,(*i),id);
						}
					}
					else if (name == "unsubscribe")
					{
						//Websocket wants to unsubscribe to an event, data.front();
						for (auto i=data.begin();i!=data.end();i++)
						{
							sinkManager->removeSink(wsi,(*i),id);
						}
					}
					else if (name == "getSupportedEventTypes")
					{
						//If data.front() dosen't contain a property name, return a list of properties supported.
						//if it does, then return the event types that particular property supports.
						string typessupported = "";
						if (data.size() == 0)
						{
							//Send what properties we support
							typessupported = "\"running_status_speedometer\",\"running_status_engine_speed\",\"running_status_steering_wheel_angle\",\"running_status_transmission_gear_status\"";
							
							PropertyList foo = sinkManager->getSupportedProperties();
							PropertyList::const_iterator i=foo.cbegin();
							while (i != foo.cend())
							{
								typessupported.append(",\"").append((*i)).append("\"");
								i++;
							}
						}
						else
						{
							//Send what events a particular property supports
							if (data.front()== "running_status_speedometer")
							{
								typessupported = "\"get\",\"subscribe\",\"unsubscribe\",\"getSupportedEventTypes\"";
							}
							else if (data.front()== "running_status_engine_speed")
							{
								typessupported = "\"get\",\"subscribe\",\"unsubscribe\",\"getSupportedEventTypes\"";
							}
							else if (data.front() == "running_status_steering_wheel_angle")
							{
								typessupported = "\"get\",\"subscribe\",\"unsubscribe\",\"getSupportedEventTypes\"";
							}
							else if (data.front() == "running_status_transmission_gear_status")
							{
								typessupported = "\"get\",\"subscribe\",\"unsubscribe\",\"getSupportedEventTypes\"";
							}
							else
							{
								PropertyList foo = sinkManager->getSupportedProperties();
								if (ListPlusPlus<VehicleProperty::Property>(&foo).contains(data.front()))
								{
									//sinkManager->addSingleShotSink(wsi,data.front(),id);
									typessupported = "\"get\",\"subscribe\",\"unsubscribe\",\"getSupportedEventTypes\"";
								}
							}
						}
						stringstream s;
						string s2;
						s << "{\"type\":\"methodReply\",\"name\":\"getSupportedEventTypes\",\"data\":[" << typessupported << "],\"transactionid\":\"" << id << "\"}";
						string replystr = s.str();
						DebugOut() << __SMALLFILE__ << ":" << __LINE__ << " JSON Reply: " << replystr << "\n";
						//printf("Reply: %s\n",replystr.c_str());
						char *new_response = new char[LWS_SEND_BUFFER_PRE_PADDING + strlen(replystr.c_str()) + LWS_SEND_BUFFER_POST_PADDING];
						new_response+=LWS_SEND_BUFFER_PRE_PADDING;
						strcpy(new_response,replystr.c_str());
						libwebsocket_write(wsi, (unsigned char*)new_response, strlen(new_response), LWS_WRITE_TEXT);
						delete (char*)(new_response-LWS_SEND_BUFFER_PRE_PADDING);
					}
					else
					{
						DebugOut(0)<<"Unknown method called."<<endl;
					}
				}
			}

			
			///TODO: this will probably explode:
			//mlc: I agree with Kevron here, it does explode.
			//if(error) g_error_free(error);

			g_object_unref(reader);
			g_object_unref(parser);


			
			break;
		}
		case LWS_CALLBACK_ADD_POLL_FD:
		{
			//printf("Adding poll %i\n",sinkManager);
			//DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Adding poll" << (int)sinkManager << "\n";
			if (sinkManager != 0)
			{
				sinkManager->addPoll((int)(long)user);
			}
			break;
		}
		case LWS_CALLBACK_DEL_POLL_FD:
		{
			sinkManager->removePoll((int)(long)user);
			break;
		}
		case LWS_CALLBACK_SET_MODE_POLL_FD:
		{
			//Set the poll mode
			break;
		}
		case LWS_CALLBACK_CLEAR_MODE_POLL_FD:
		{
			//Don't handle this yet.
			break;
		}
		default:
		{
			//printf("Unhandled callback: %i\n",reason);
			DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Unhandled callback:" << reason << "\n";
			break;
		}
	}
	return 0; 
}