/*
 * Copyright © 2012-2013 Canonical Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authored by: Antti Kaijanmäki <antti.kaijanmaki@canonical.com>
 */
#ifndef PLATFORM_MANAGER_NMOFONO_URFKILL_H
#define PLATFORM_MANAGER_NMOFONO_URFKILL_H

#include <core/dbus/bus.h>
#include <core/dbus/object.h>
#include <core/dbus/property.h>
#include <core/dbus/service.h>
#include <core/dbus/types/object_path.h>
#include <core/dbus/types/any.h>
#include <core/dbus/types/struct.h>
#include <core/dbus/types/stl/map.h>
#include <core/dbus/types/stl/string.h>
#include <core/dbus/types/stl/tuple.h>
#include <core/dbus/types/stl/vector.h>

namespace org
{
namespace freedesktop
{
namespace URfkill {

    struct Interface {
        struct URfkill
        {
            static const std::string& name()
            {
                static const std::string s{"org.freedesktop.URfkill"};
                return s;
            }

            struct Method
            {
                struct Block
                {
                    static const std::string& name()
                    {
                        static const std::string s{"Block"};
                        return s;
                    }

                    typedef URfkill Interface;

                    static std::chrono::milliseconds default_timeout()
                    {
                        return std::chrono::seconds{1};
                    }
                };

                struct EnumerateDevices
                {
                    static const std::string& name()
                    {
                        static const std::string s{"EnumerateDevices"};
                        return s;
                    }

                    typedef URfkill Interface;
                    typedef std::vector<core::dbus::types::ObjectPath> ResultType;

                    static std::chrono::milliseconds default_timeout()
                    {
                        return std::chrono::seconds{1};
                    }
                };
            };

            bool block(std::uint32_t type,
                       bool block)
            {
                auto result =
                        object->invoke_method_synchronously<
                        Method::Block,
                        bool>(type, block);

                if (result.is_error())
                    throw std::runtime_error(result.error().print());

                return result.value();
            }

            Method::EnumerateDevices::ResultType
            enumerate_devices()
            {
                auto result =
                        object->invoke_method_synchronously<
                        Method::EnumerateDevices,
                        Method::EnumerateDevices::ResultType>();

                if (result.is_error())
                    throw std::runtime_error(result.error().print());

                return result.value();
            }

            URfkill(std::shared_ptr<core::dbus::Service> &service,
                    std::shared_ptr<core::dbus::Object> &object)
                : service(service),
                  object(object)
            {
            }

            std::shared_ptr<core::dbus::Service> service;
            std::shared_ptr<core::dbus::Object> object;
        };

        struct Device
        {
            static const std::string& name()
            {
                static const std::string s{"org.freedesktop.URfkill.Device"};
                return s;
            }

            struct Property
            {
                struct Hard
                {
                    static const std::string& name()
                    {
                        static const std::string s{"hard"};
                        return s;
                    }

                    typedef Device Interface;
                    typedef bool ValueType;
                    static const bool readable = true;
                    static const bool writable = false;
                };

                struct Soft
                {
                    static const std::string& name()
                    {
                        static const std::string s{"soft"};
                        return s;
                    }

                    typedef Device Interface;
                    typedef bool ValueType;
                    static const bool readable = true;
                    static const bool writable = false;
                };
            };

            Device(const std::shared_ptr<core::dbus::Object>& object)
                : object(object),
                  hard(object->get_property<Property::Hard>()),
                  soft(object->get_property<Property::Soft>())
            {}

            std::shared_ptr<core::dbus::Object> object;

            std::shared_ptr<core::dbus::Property<Property::Hard>> hard;
            std::shared_ptr<core::dbus::Property<Property::Soft>> soft;
        };
    };

    struct Service
    {
        std::shared_ptr<Interface::URfkill> urfkill;

        Service(const core::dbus::Bus::Ptr& bus)
        {
            auto service = core::dbus::Service::use_service<Interface::URfkill>(bus);
            auto object = service->object_for_path(core::dbus::types::ObjectPath("/org/freedesktop/URfkill"));
            urfkill = std::make_shared<Interface::URfkill>(service, object);
        }

        struct Mock
        {
            std::shared_ptr<Interface::URfkill> urfkill;

            Mock(const core::dbus::Bus::Ptr& bus)
            {
                auto service = core::dbus::Service::add_service<Interface::URfkill>(bus);
                auto object = service->add_object_for_path(core::dbus::types::ObjectPath("/org/freedesktop/URfkill"));
                urfkill = std::make_shared<Interface::URfkill>(service, object);
            }
        };
    };
}
}
}

#endif // PLATFORM_MANAGER_NMOFONO_URFKILL_H
