/*
 * Copyright Staffan Gimåker 2008-2010.
 *
 * ---
 *
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 */

#ifndef PEEKABOT_CLIENT_PEEKABOT_PROXY_BASE_HH_INCLUDED
#define PEEKABOT_CLIENT_PEEKABOT_PROXY_BASE_HH_INCLUDED


#include <stdexcept>
#include <boost/shared_ptr.hpp>
#include <boost/thread/recursive_mutex.hpp>

#include "../../Visibility.hh"
#include "../../Types.hh"
#include "../OperationResult.hh"


namespace peekabot
{
    class Action;

    namespace client
    {
        class Status;
        class ClientImpl;
        class PeekabotClient;

        /**
         * \brief Base class for all client proxies.
         *
         * Provides operations common to all proxies, be it object proxies or,
         * say, GUI-related proxies. Most notably, it provides methods for
         * dispatching (sending) actions, including actions for "get
         * operations".
         *
         * Each client proxy has a client associated with it, which is used for
         * dispatching actions etc. If unassigned (e.g. if default constructed)
         * no client is associated with the proxy, and any attempts to use
         * the client will generate an exception.
         */
        class PEEKABOT_API PeekabotProxyBase
        {
        public:
            virtual ~PeekabotProxyBase();

            /**
             * \brief Get the client associated with this proxy.
             *
             * \throw std::logic_error Thrown if the proxy is not associated
             * with a client.
             */
            PeekabotClient get_client() const;

            /**
             * \brief Returns true if the proxy has been assigned.
             */
            bool is_assigned() const;

        protected:
            PEEKABOT_HIDDEN PeekabotProxyBase();

            PEEKABOT_HIDDEN PeekabotProxyBase(const PeekabotProxyBase &p);

            /**
             * \brief Set the client associated with this proxy.
             */
            PEEKABOT_HIDDEN void set_client_impl(
                boost::shared_ptr<ClientImpl> client);

            PEEKABOT_HIDDEN boost::shared_ptr<ClientImpl>
                unchecked_get_client_impl() const;

            static boost::shared_ptr<ClientImpl> unchecked_get_client_impl(
                const PeekabotProxyBase &p);

            PEEKABOT_HIDDEN boost::shared_ptr<ClientImpl> get_client_impl()
                const;

            static boost::shared_ptr<ClientImpl> get_client_impl(
                const PeekabotProxyBase &p);

            static boost::shared_ptr<ClientImpl> get_client_impl(
                PeekabotClient &client);

            /**
             * \brief Dispatch (send) an action.
             *
             * This method simply forwards what's passed to it to
             * PeekabotClient. Refer to
             * PeekabotClient::dispatch_ation(Action *, Status *, bool) for
             * documentation.
             */
            PEEKABOT_HIDDEN void dispatch_action(
                Action *action, Status *status) const;

            /**
             * \brief Dispatch (send) a get-action.
             *
             * This method simply forwards what's passed to it to
             * PeekabotClient. Refer to
             * PeekabotClient::dispatch_get_ation(Action *, Status *, bool) for
             * documentation.
             */
            PEEKABOT_HIDDEN boost::shared_ptr<OperationResult>
                dispatch_get_action(Action *action, uint32_t request_id) const;

            /**
             * \brief Allocate a request ID, used for track statuses and
             * results.
             *
             * Each status and result request has a request ID tied to it. Such
             * IDs can be generated by this method. For status requests
             * allocation of request IDs is implicit, but when dealing with
             * result requests an ID has to be allocated manually (see
             * dispatch_get_action(Action *, uint32_t)).
             *
             * \return A unique request ID.
             */
            PEEKABOT_HIDDEN uint32_t allocate_request_id() const;

        private:
            // Intentionally only declared and not defined!
            PEEKABOT_HIDDEN PeekabotProxyBase &operator=(const PeekabotProxyBase &other);

        protected:
            /**
             * \brief Governs access to ALL members of the class.
             *
             * To keep memory consumption down, derived classes are encouraged
             * to use the same mutex for syncrhonizing access to their members.
             */
            mutable boost::recursive_mutex m_mutex;

        private:
            mutable boost::shared_ptr<ClientImpl> m_client_impl;
        };
    }
}


#endif // PEEKABOT_CLIENT_PEEKABOT_PROXY_BASE_HH_INCLUDED
