/*
 * Copyright Staffan Gimåker 2006-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_STATUS_HH_INCLUDED
#define PEEKABOT_CLIENT_STATUS_HH_INCLUDED


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

#include "../Visibility.hh"
#include "OperationStatus.hh"


namespace peekabot
{
    namespace client
    {
        /**
         * \brief Provides a \e thread-safe way for surveying the outcome,
         * henceforth referred to as status, of \e one operation (action).
         *
         * It provides the "end user" with methods for querying whether a
         * status is yet available and blocking until a status is available.
         *
         * \sa Result, DelayedDispatch, OperationStatus
         */
        class PEEKABOT_API Status
        {
        public:
            /**
             * \brief Create an unused status object, not initially associated
             * with an operation.
             */
            Status();


            /**
             * \brief Create a status object tracking the outcome of the
             * operation associated with the given OperationStatus object.
             *
             * \param status The OperationStatus object associated with the
             * operation to track.
             */
            Status(boost::shared_ptr<OperationStatus> status);


            virtual ~Status();


            Status &operator=(
                boost::shared_ptr<OperationStatus> status);

            /**
             * \brief Get the operation's outcome.
             *
             * \pre Defined only when has_completed() is \c true. The object
             * must also not be unused.
             *
             * \throw std::logic_error Thrown if the preconditions are not met.
             */
            OperationOutcome get_outcome() const;

            /**
             * \brief Get whether the operation's status is available.
             *
             * \pre The object is not unused, e.g. it tracks the outcome of an
             * operation.
             *
             * \throw std::logic_error The status object is unused.
             */
            bool has_completed() const;

            /**
             * \brief Waits until the operation has completed and returns
             * \c true if it succeeded.
             *
             * \pre The object is not unused, e.g. it tracks the outcome of an
             * operation.
             *
             * \throw std::logic_error The status object is unused.
             */
            bool succeeded() const;

            /**
             * \brief Waits until the operation has completed and returns
             * \c false if it failed.
             *
             * Note if the operation succeeds but the client is disconnected
             * before the client is notified failed() will return true, even
             * though the operation didn't really fail.
             *
             * \pre The object is not unused, e.g. it tracks the outcome of an
             * operation.
             *
             * \throw std::logic_error The status object is unused.
             */
            bool failed() const;

            /**
             * \brief Wait until has_completed() is \c true.
             *
             * If the operation outcome is already available the method will
             * return promptly.
             *
             * \pre The object is not unused, e.g. it tracks the outcome of an
             * operation.
             *
             * \return Returns \c true if the client was disconnected before
             * a response was received, \c false otherwise.
             *
             * \throw std::logic_error The status object is unused.
             */
            bool wait_until_completed() const;

            /**
             * \brief Return's the error message in case of failure.
             *
             * \pre Defined only when the outcome is \c OPERATION_FAILED.
             *
             * \throw std::logic_error The status object is unused.
             */
            std::string get_error_message() const;

        private:
            /**
             * \brief The object internally storing the data pertaining to the
             * operation being tracked.
             *
             * Defined only when if the assignment operator or non-default
             * constructor is called.
             */
            boost::shared_ptr<OperationStatus> m_status;
        };
    }
}


#endif // PEEKABOT_CLIENT_STATUS_HH_INCLUDED
