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.");
	}
}
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.");	
}
void AbstractDBusInterface::handleMyMethodCall(GDBusConnection       *connection,
							 const gchar           *sender,
							 const gchar           *object_path,
							 const gchar           *interface_name,
							 const gchar           *method_name,
							 GVariant              *parameters,
							 GDBusMethodInvocation *invocation,
							 gpointer               user_data)
{

	std::string method = method_name;
	AbstractDBusInterface* iface = static_cast<AbstractDBusInterface*>(user_data);

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

	g_assert(iface);

	if(std::string(interface_name) == "org.freedesktop.DBus.Properties")
	{
		if(method == "Get")
		{
			gchar* propertyName = nullptr;
			gchar* ifaceName = nullptr;
			g_variant_get(parameters, "(ss)", &ifaceName, &propertyName);

			DebugOut(6) << "Parameter signature: " << g_variant_get_type_string(parameters) << endl;
//			DebugOut(6) << "Get property " << propertyName << " for interface " << ifaceName << endl;

			GError* error = nullptr;
			auto value = AbstractDBusInterface::getProperty(connection, sender, object_path, ifaceName, propertyName, &error, iface);
			amb::make_super(error);

			if(!value)
			{
				g_dbus_method_invocation_return_dbus_error(invocation, std::string(std::string(ifaceName)+".PropertyNotFound").c_str(), "Property not found in interface");
			}

			g_dbus_method_invocation_return_value(invocation, g_variant_new("(v)", value));
			return;
		}
		else if(method == "GetAll")
		{
			gchar* ifaceName = nullptr;
			g_variant_get(parameters, "(s)", &ifaceName);

			GVariantBuilder builder;
			g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));

			auto propertyMap = iface->getProperties();

			for(auto itr : propertyMap)
			{
				auto prop = itr.second;
				GError* error = nullptr;
				auto value = AbstractDBusInterface::getProperty(connection, sender, object_path, ifaceName, prop->name().c_str(), &error, iface);
				amb::make_super(error);
				g_variant_builder_add(&builder, "{sv}", prop->name().c_str(), g_variant_new("v", value));
				//sequence
				auto sequence = AbstractDBusInterface::getProperty(connection, sender, object_path, ifaceName, std::string(prop->name()+"Sequence").c_str(), &error, iface);
				g_variant_builder_add(&builder, "{sv}", std::string(prop->name()+"Sequence").c_str(), g_variant_new("v", sequence));

				auto quality = AbstractDBusInterface::getProperty(connection, sender, object_path, ifaceName, std::string(prop->name()+"ValueQuality").c_str(), &error, iface);
				g_variant_builder_add(&builder, "{sv}", std::string(prop->name()+"ValueQuality").c_str(), g_variant_new("v", quality));

				auto freq = AbstractDBusInterface::getProperty(connection, sender, object_path, ifaceName, std::string(prop->name()+"UpdateFrequency").c_str(), &error, iface);
				g_variant_builder_add(&builder, "{sv}", std::string(prop->name()+"UpdateFrequency").c_str(), g_variant_new("v", freq));
			}

			auto time = AbstractDBusInterface::getProperty(connection, sender, object_path, ifaceName, "Time", nullptr, iface);
			auto zone = AbstractDBusInterface::getProperty(connection, sender, object_path, ifaceName, "Zone", nullptr, iface);
			g_variant_builder_add(&builder, "{sv}", "Time", g_variant_new("v", time));
			g_variant_builder_add(&builder, "{sv}", "Zone", g_variant_new("v", zone));

			g_dbus_method_invocation_return_value(invocation, g_variant_new("(a{sv})", &builder));
			return;
		}
		else if(method == "Set")
		{
			gchar* ifaceName = nullptr;
			gchar* propName = nullptr;
			GVariant* value;
			g_variant_get(parameters, "(ssv)", &ifaceName, &propName, &value);

			AbstractDBusInterface::setProperty(connection, sender, object_path, ifaceName, propName, value, nullptr, iface,
											   [&invocation, &ifaceName](bool success, AsyncPropertyReply::Error error) {
				if(success)
				{
					g_dbus_method_invocation_return_value(invocation, nullptr);
				}
				else
				{
					g_dbus_method_invocation_return_dbus_error(invocation, ifaceName, AsyncPropertyReply::errorToStr(error).c_str());
				}
			});
			return;
		}
	}
	else if(method == "GetHistory")
	{
		double beginTime = 0;
		double endTime = 0;

		g_variant_get(parameters, "(dd)", &beginTime, &endTime);

		auto propertyMap = iface->getProperties();

		PropertyList propertyList;

		for(auto itr = propertyMap.begin(); itr != propertyMap.end(); itr++)
		{
			VariantType* prop = (*itr).second;

			if(!contains(propertyList, prop->ambPropertyName()))
				propertyList.push_back(prop->ambPropertyName());
		}

		std::string ifaceName = iface->interfaceName();

		AsyncRangePropertyRequest request;

		request.properties = propertyList;
		request.timeBegin = beginTime;
		request.timeEnd = endTime;
		request.zone = iface->zone();
		//request.sourceUuid = iface->source();

		request.completed = [&invocation,&ifaceName](AsyncRangePropertyReply* r)
		{
			auto reply = amb::make_unique(r);
			if(!reply->success)
			{
				stringstream str;
				str<<"Error during request: "<<AsyncPropertyReply::errorToStr(reply->error);
				ifaceName += ".Error";
				g_dbus_method_invocation_return_dbus_error(invocation, ifaceName.c_str(), str.str().c_str());
				return;
			}

			if(!reply->values.size())
			{
				ifaceName += ".Error";
				g_dbus_method_invocation_return_dbus_error(invocation, ifaceName.c_str(), "No results");
				return;
			}

			GVariantBuilder builder;
			g_variant_builder_init(&builder, G_VARIANT_TYPE("a{svd}"));


			for(auto itr = reply->values.begin(); itr != reply->values.end(); itr++)
			{
				AbstractPropertyType* value = *itr;

				g_variant_builder_add(&builder, "{svd}", value->name.c_str(), g_variant_ref(value->toVariant()),value->timestamp);
			}

			g_dbus_method_invocation_return_value(invocation,g_variant_new("(a{svd})",&builder));
		};

		iface->re->getRangePropertyAsync(request);

		return;
	}

	g_dbus_method_invocation_return_error(invocation,G_DBUS_ERROR,G_DBUS_ERROR_UNKNOWN_METHOD, "Unknown method.");
}