static void signalCallback( GDBusConnection *connection,
							const gchar *sender_name,
							const gchar *object_path,
							const gchar *interface_name,
							const gchar *signal_name,
							GVariant *parameters,
							gpointer user_data)
{
	AutomotiveManager* manager = static_cast<AutomotiveManager*>(user_data);

	if(!manager)
	{
		DebugOut(DebugOut::Error)<<"Bad user_data"<<endl;
		return;
	}

	gchar* name=nullptr;
	gchar* newOwner=nullptr;
	gchar* oldOwner = nullptr;
	g_variant_get(parameters,"(sss)",&name, &oldOwner, &newOwner);

	std::list<AbstractDBusInterface*> toRemove;

	if(std::string(newOwner) == "")
	{
		for(auto &i : manager->subscribedProcesses)
		{
			AbstractDBusInterface* iface = i.first;

			for(auto itr = i.second.begin(); itr != i.second.end(); itr++)
			{
				std::string n = *itr;
				if(n == name)
				{
					DebugOut()<<"unreferencing "<<n<<" from the subscription of "<<iface->objectPath()<<endl;
					itr = manager->subscribedProcesses[iface].erase(itr);
					DebugOut()<<"new ref count: "<<manager->subscribedProcesses[iface].size()<<endl;
				}
			}

			if(manager->subscribedProcesses[iface].empty())
			{
				DebugOut()<<"No more subscribers.  Unregistering: "<<iface->objectPath()<<endl;
				///Defer removal to not screw up the list
				toRemove.push_back(iface);
				iface->unregisterObject();
			}
		}

		for(auto & i : toRemove)
		{
			manager->subscribedProcesses.erase(i);
		}
	}

	g_free(name);
	g_free(newOwner);
	g_free(oldOwner);
}
static void signalCallback( GDBusConnection *connection,
																												 const gchar *sender_name,
																												 const gchar *object_path,
																												 const gchar *interface_name,
																												 const gchar *signal_name,
																												 GVariant *parameters,
																												 gpointer user_data)
{
	AutomotiveManager* manager = static_cast<AutomotiveManager*>(user_data);

	gchar* name=nullptr;
	gchar* newOwner=nullptr;
	gchar* oldOwner = nullptr;
	g_variant_get(parameters,"(sss)",&name, &oldOwner, &newOwner);

	if(std::string(newOwner) == "")
	{
		for(auto i : manager->subscribedProcesses)
		{
			AbstractDBusInterface* iface = i.first;
			for(auto n : i.second)
			{
				if(n == name)
				{
					DebugOut()<<"unreferencing "<<n<<" from the subscription of "<<iface->objectPath()<<endl;
					manager->subscribedProcesses[iface].remove(n);
				}
			}

			if(manager->subscribedProcesses[iface].empty())
			{
				DebugOut()<<"No more subscribers.  Unregistering."<<endl;
				iface->unregisterObject();
			}
		}
	}

	g_free(name);
	g_free(newOwner);
	g_free(oldOwner);
}
static void handleMethodCall(GDBusConnection       *connection,
							 const gchar           *sender,
							 const gchar           *object_path,
							 const gchar           *interface_name,
							 const gchar           *method_name,
							 GVariant              *parameters,
							 GDBusMethodInvocation *invocation,
							 gpointer               user_data)
{

	AutomotiveManager* manager = static_cast<AutomotiveManager*>(user_data);

	std::string method = method_name;

	if(method == "findProperty")
	{
		DebugOut(DebugOut::Warning)<<"org.automotive.Manager.findProperty() is deprecated.  Use org.automotive.Manager.FindObject() instead."<<endl;

		gchar* arg;

		g_variant_get(parameters,"(s)",&arg);

		std::string objectToFind = arg;

		if(objectToFind == "")
		{
			g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
			return;
		}

		std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(objectToFind);

		if(!interfaces.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.PropertyNotFound", "Object not found");
			return;
		}

		auto itr = interfaces.begin();

		g_dbus_method_invocation_return_value(invocation, g_variant_new("(o)",(*itr)->objectPath().c_str()));
		///TODO: we might need to clean up stuff there (like var)
	}

	else if(method == "FindObject")
	{
		gchar* arg;

		g_variant_get(parameters,"(s)",&arg);

		std::string objectToFind = arg;

		if(objectToFind == "")
		{
			g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
			return;
		}

		std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(objectToFind);

		if(!interfaces.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Object not found");
			return;
		}

		GVariantBuilder params;
		g_variant_builder_init(&params, G_VARIANT_TYPE_ARRAY);

		for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
		{
			AbstractDBusInterface* t = *itr;
			if(!t->isSupported())
				continue;
			GVariant *newvar = g_variant_new("o",t->objectPath().c_str());
			g_variant_builder_add_value(&params, newvar);

		}

		//GVariant* var =  g_variant_builder_end(&params);

		g_dbus_method_invocation_return_value(invocation, g_variant_new("(ao)",&params));
		///TODO: we might need to clean up stuff there (like var)
	}

	else if(method == "FindObjectForZone")
	{
		gchar* arg;
		int zone;

		g_variant_get(parameters,"(si)", &arg, &zone);

		std::string propertyToFind = arg;

		if(propertyToFind == "")
		{
			g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
			return;
		}

		std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(propertyToFind);

		if(!interfaces.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
			return;
		}



		for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
		{
			AbstractDBusInterface* t = *itr;
			if(t->zone() == (Zone::Type)zone)
			{
				g_dbus_method_invocation_return_value(invocation,g_variant_new("(o)", t->objectPath().c_str()));
				return;
			}
		}

		g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
	}

	else if (method == "ZonesForObjectName")
	{
		gchar* arg;

		g_variant_get(parameters,"(s)",&arg);

		std::string propertyToFind = arg;

		if(propertyToFind == "")
		{
			g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
			return;
		}

		std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(propertyToFind);

		if(!interfaces.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
			return;
		}

		GVariantBuilder params;
		g_variant_builder_init(&params, G_VARIANT_TYPE_ARRAY);

		for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
		{
			AbstractDBusInterface* t = *itr;
			GVariant *newvar = g_variant_new("i",t->zone());
			g_variant_builder_add_value(&params, newvar);

		}

		g_dbus_method_invocation_return_value(invocation,g_variant_new("(ai)",&params));
	}
	
	else if(method == "List")
	{
		std::list<AbstractDBusInterface*> list = AbstractDBusInterface::interfaces();

		if(!list.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.Error", "No supported objects");
			return;
		}

		GVariantBuilder builder;
		g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);


		for(auto itr = list.begin(); itr != list.end(); itr++)
		{
			if(!(*itr)->isSupported())
				continue;

			std::string objectName = (*itr)->objectName();

			g_variant_builder_add(&builder, "s", objectName.c_str());
		}


		g_dbus_method_invocation_return_value(invocation,g_variant_new("(as)",&builder));
	}

	g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");	
}
static void handleMethodCall(GDBusConnection       *connection,
							 const gchar           *sender,
							 const gchar           *object_path,
							 const gchar           *interface_name,
							 const gchar           *method_name,
							 GVariant              *parameters,
							 GDBusMethodInvocation *invocation,
							 gpointer               user_data)
{

	AutomotiveManager* manager = static_cast<AutomotiveManager*>(user_data);

	std::string method = method_name;

	uint pid = getPid(sender);

	if(DebugOut::getDebugThreshhold() >= 6)
	{
		DebugOut(6)<<"DBus method call from: "<<sender<< " pid: " <<pid<< " interface: "<<interface_name<<" method: "<<method<<endl;
		DebugOut(6)<<"DBus method call path: "<<object_path<<endl;
	}

	if(method == "FindObject")
	{
		gchar* arg;

		g_variant_get(parameters,"(s)",&arg);

		std::string objectToFind = arg;

		if(objectToFind == "")
		{
			g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
			return;
		}

		std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(objectToFind);

		if(!interfaces.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Object not found");
			return;
		}

		GVariantBuilder params;
		g_variant_builder_init(&params, G_VARIANT_TYPE_ARRAY);

		bool hasItems = false;

		for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
		{
			AbstractDBusInterface* t = *itr;
			if(!t->isSupported())
				continue;

			hasItems = true;

			if(!t->isRegistered())
				t->registerObject();

			std::list<std::string> processes = manager->subscribedProcesses[t];

			if(!contains(processes,sender))
			{
				DebugOut()<<"Referencing "<<t->objectPath()<<" with sender: "<<sender<<endl;
				manager->subscribedProcesses[t].push_back(sender);
			}

			GVariant *newvar = g_variant_new("o",t->objectPath().c_str());
			g_variant_builder_add_value(&params, newvar);
		}

		if(hasItems)
			g_dbus_method_invocation_return_value(invocation, g_variant_new("(ao)",&params));
		else
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");

	}

	else if(method == "FindObjectForZone")
	{
		gchar* arg;
		int zone;

		g_variant_get(parameters,"(si)", &arg, &zone);

		std::string propertyToFind = arg;

		if(propertyToFind == "")
		{
			g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
			return;
		}

		std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(propertyToFind);

		if(!interfaces.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation, "org.automotive.Manager.ObjectNotFound", "Property not found");
			return;
		}



		for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
		{
			AbstractDBusInterface* t = *itr;

			if(t->zone() == (Zone::Type)zone)
			{
				if(!t->isRegistered())
					t->registerObject();

				std::list<std::string> processes = manager->subscribedProcesses[t];

				if(!contains(processes,sender))
				{
					DebugOut()<<"Referencing "<<t->objectPath()<<" with sender: "<<sender<<endl;
					manager->subscribedProcesses[t].push_back(sender);
				}

				g_dbus_method_invocation_return_value(invocation,g_variant_new("(o)", t->objectPath().c_str()));
				return;
			}
		}

		g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.InvalidZone", "zone not found");
	}

	else if (method == "ZonesForObjectName")
	{
		gchar* arg;

		g_variant_get(parameters,"(s)",&arg);

		std::string propertyToFind = arg;

		if(propertyToFind == "")
		{
			g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
			return;
		}

		std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(propertyToFind);

		if(!interfaces.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
			return;
		}

		GVariantBuilder params;
		g_variant_builder_init(&params, G_VARIANT_TYPE_ARRAY);

		for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
		{
			AbstractDBusInterface* t = *itr;
			GVariant *newvar = g_variant_new("i",t->zone());
			g_variant_builder_add_value(&params, newvar);

		}

		g_dbus_method_invocation_return_value(invocation,g_variant_new("(ai)",&params));
	}

	else if(method == "List")
	{
		std::list<AbstractDBusInterface*> list = AbstractDBusInterface::interfaces();

		if(!list.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.Error", "No supported objects");
			return;
		}

		GVariantBuilder builder;
		g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);


		for(auto itr = list.begin(); itr != list.end(); itr++)
		{
			if(!(*itr)->isSupported())
				continue;

			std::string objectName = (*itr)->objectName();

			g_variant_builder_add(&builder, "s", objectName.c_str());
		}


		g_dbus_method_invocation_return_value(invocation,g_variant_new("(as)",&builder));
	}
	else if(method == "SourcesForObjectName")
	{
		gchar* arg;

		g_variant_get(parameters,"(s)",&arg);

		std::string propertyToFind = arg;

		if(propertyToFind == "")
		{
			g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
			return;
		}

		std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(propertyToFind);

		if(!interfaces.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
			return;
		}

		GVariantBuilder params;
		g_variant_builder_init(&params, G_VARIANT_TYPE_ARRAY);

		for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
		{
			AbstractDBusInterface* t = *itr;
			string source = t->source();
			boost::algorithm::erase_all(source, "-");
			GVariant *newvar = g_variant_new("s", source.c_str());
			g_variant_builder_add_value(&params, newvar);

		}

		g_dbus_method_invocation_return_value(invocation,g_variant_new("(as)",&params));
	}
	else if(method == "FindObjectForSourceZone")
	{
		gchar* arg;
		gchar* arg2;
		int zone;

		g_variant_get(parameters,"(ssi)", &arg, &arg2, &zone);

		std::string propertyToFind = arg;
		std::string source = arg2;

		if(propertyToFind == "" || source == "")
		{
			g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_INVALID_ARGS, "Invalid argument.");
			return;
		}

		std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(propertyToFind);

		if(!interfaces.size())
		{
			g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
			return;
		}

		for(auto itr = interfaces.begin(); itr != interfaces.end(); itr++)
		{
			AbstractDBusInterface* t = *itr;
			string targetSource = t->source();
			boost::algorithm::erase_all(targetSource, "-");
			if(t->zone() == (Zone::Type)zone && source == targetSource)
			{
				if(!t->isRegistered())
					t->registerObject();

				std::list<std::string> processes = manager->subscribedProcesses[t];

				if(!contains(processes,sender))
				{
					DebugOut()<<"Referencing "<<t->objectPath()<<" with sender: "<<sender<<endl;
					manager->subscribedProcesses[t].push_back(sender);
				}

				g_dbus_method_invocation_return_value(invocation,g_variant_new("(o)", t->objectPath().c_str()));
				return;
			}
		}

		g_dbus_method_invocation_return_dbus_error(invocation,"org.automotive.Manager.ObjectNotFound", "Property not found");
	}
	else if(method == "SupportsProperty")
	{
		gchar* objectName;
		gchar* propertyToFindStr;

		g_variant_get(parameters,"(ss)",&objectName, &propertyToFindStr);

		auto objectNamePtr = amb::make_super(objectName);
		auto propertyToFindStrPtr = amb::make_super(propertyToFindStr);

		DebugOut(6) << "Checking " << objectNamePtr.get() << " for member: " << propertyToFindStrPtr.get() << endl;

		std::list<AbstractDBusInterface*> interfaces = AbstractDBusInterface::getObjectsForProperty(objectNamePtr.get());

		for(auto i : interfaces)
		{
			if(i->hasPropertyDBus(propertyToFindStrPtr.get()))
			{
				DebugOut(6) << "member " << propertyToFindStrPtr.get() << " of " << objectNamePtr.get() << " was found!!" << endl;
				g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", true));
				return;
			}
		}
		DebugOut(6) << "member " << propertyToFindStrPtr.get() << " of " << objectNamePtr.get() << " was not found." << endl;
		g_dbus_method_invocation_return_value(invocation,g_variant_new("(b)", false));
	}
	else
	{
		g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");
	}
}