/*
 * Copyright Staffan Gimåker 2007-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_RESULT_HH_INCLUDED
#define PEEKABOT_CLIENT_RESULT_HH_INCLUDED


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

#include "../Any.hh"
#include "OperationResult.hh"
#include "Status.hh"


namespace peekabot
{
    namespace client
    {
        /**
         * \brief Encapsulates a result from an operation, such
         * as getting an object's color, executed remotely on the server.
         *
         * It is built on top of Status -- which provide a mean to know
         * whether the result is available for reading. The actual result
         * cannot be gotten from the Result object until get_outcome() signals
         * success.
         */
        template<class T>
        class Result : public Status
        {
        public:
            /**
             * \brief Create an unused result object, not associated with the
             * result from an operation.
             */
            Result() : Status() {}

            virtual ~Result() {}

            /**
             * \brief Create a result object from an OperationResult.
             */
            Result(boost::shared_ptr<OperationResult> result)
                : Status(result),
                  m_result(result)
            {
            }

            /**
             * \brief Return a copy of the result stored in the Result object.
             *
             * \exception std::logic_error Thrown if 1) the operation failed
             * or 2) the outcome operation is still pending.
             * \exception std::runtime_error Thrown if the actual type of the
             * result and the requested type T doesn't match (this implies a
             * bug is lurking elsewhere).
             */
            const T get_result() const
            {
                try
                {
                    return any_cast<T>(m_result->get_result());
                }
                catch(BadAnyCast &)
                {
                    throw std::runtime_error(
                        "The specified and actual result types mismatch");
                }
            }

        private:
            /**
             * \brief The object internally storing the data pertaining to the
             * operation's result.
             *
             * Defined only when the object is constructed from a non-default
             * constructor or has been assigned from another object with a
             * valid m_result member.
             */
            boost::shared_ptr<OperationResult> m_result;
        };
    }
}


#endif // PEEKABOT_CLIENT_RESULT_HH_INCLUDED
