UncategorizedPropertyInterface::UncategorizedPropertyInterface(VehicleProperty::Property prop, AbstractRoutingEngine *re, GDBusConnection *connection)
	:DBusSink(prop, re, connection, map<string, string>())
{
	AbstractPropertyType* temp = VehicleProperty::getPropertyTypeForPropertyNameValue(prop);

	if(!temp)
	{
		throw std::runtime_error("Cannot create uncategorized property: " + prop);
	}

	GVariant* var = temp->toVariant();
	std::string signature = g_variant_get_type_string(var);
	g_variant_unref(var);

	propertyDBusMap[prop] = new VariantType(re, signature, prop, prop, VariantType::ReadWrite);

	delete temp;


}
AbstractPropertyType* VehicleProperty::getPropertyTypeForPropertyNameValue(VehicleProperty::Property name, std::string value)
{
	if(registeredPropertyFactoryMap.count(name) > 0)
	{
		VehicleProperty::PropertyTypeFactoryCallback cb = registeredPropertyFactoryMap[name];
		if ( cb != NULL )
		{
			AbstractPropertyType* type = cb();
			if(type == NULL)
				throw std::runtime_error("Cannot return NULL in a PropertyTypeFactory");

			if(value != "" )
				type->fromString(value);

			return type;
		}
	}

	DebugOut(DebugOut::Error)<<"Property not found"<<endl;

	return nullptr;
}
void VariantType::fromGVariant(GVariant *val)
{
	AbstractPropertyType *v = VehicleProperty::getPropertyTypeForPropertyNameValue(mAmbPropertyName);
	v->fromVariant(val);

	AsyncSetPropertyRequest request;
	request.property = mAmbPropertyName;
	request.value = v;
	request.zoneFilter = mZoneFilter;
	request.completed = [&](AsyncPropertyReply* reply)
	{
		/// TODO: throw dbus exception
		if(!reply->success)
		{
			DebugOut(DebugOut::Error)<<"SetProperty fail: "<<reply->error<<endl;
		}
		///TODO: we segfault here.
		///if(v) delete v;
		delete reply;
	};

	routingEngine->setProperty(request);
}
	request.properties = reqlist;
	request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
	{
		if(!reply->success)
		{
			DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
			return;
		}

		if(cbFunction.isFunction())
		{
			QVariantList list;

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

				list.append(gvariantToQVariant(val->toVariant()));
			}

			cbFunction.call(QScriptValue(),cbFunction.engine()->newVariant(list));

		}

		delete reply;
	};

	routingEngine->getRangePropertyAsync(request);
}

void BluemonkeySink::createCustomProperty(QString name, QScriptValue defaultValue)
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.");
}