/* Copyright 2012. Bloomberg Finance L.P.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:  The above
 * copyright notice and this permission notice shall be included in all copies
 * or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */
// blpapi_resolutionlist.h                                            -*-C++-*-
#ifndef INCLUDED_BLPAPI_RESOLUTIONLIST
#define INCLUDED_BLPAPI_RESOLUTIONLIST

//@PURPOSE: Provide a representation of a list of topics.
//
//@CLASSES:
// blpapi::ResolutionList: Represents a list of topics
//
//@SEE_ALSO: blpapi_event
//
//@DESCRIPTION: This component implements a list of topics that require
// resolution.

#ifndef INCLUDED_BLPAPI_TYPES
#include <blpapi_types.h>
#endif

#ifndef INCLUDED_BLPAPI_CORRELATIONID
#include <blpapi_correlationid.h>
#endif

#ifndef INCLUDED_BLPAPI_DEFS
#include <blpapi_defs.h>
#endif

#ifndef INCLUDED_BLPAPI_ELEMENT
#include <blpapi_element.h>
#endif

#ifndef INCLUDED_BLPAPI_NAME
#include <blpapi_name.h>
#endif

#ifndef INCLUDED_BLPAPI_MESSAGE
#include <blpapi_message.h>
#endif

#include <stddef.h>

struct blpapi_ResolutionList;
typedef struct blpapi_ResolutionList blpapi_ResolutionList_t;

#ifdef __cplusplus
extern "C" {
#endif

BLPAPI_EXPORT
blpapi_Element_t *blpapi_ResolutionList_extractAttributeFromResolutionSuccess(
        const blpapi_Message_t *message, const blpapi_Name_t *attribute);

BLPAPI_EXPORT
blpapi_ResolutionList_t *blpapi_ResolutionList_create(
        blpapi_ResolutionList_t *from);

BLPAPI_EXPORT
void blpapi_ResolutionList_destroy(blpapi_ResolutionList_t *list);

BLPAPI_EXPORT
int blpapi_ResolutionList_add(blpapi_ResolutionList_t *list,
        const char *topic,
        const blpapi_CorrelationId_t *correlationId);

BLPAPI_EXPORT
int blpapi_ResolutionList_addFromMessage(blpapi_ResolutionList_t *list,
        const blpapi_Message_t *topic,
        const blpapi_CorrelationId_t *correlationId);

BLPAPI_EXPORT
int blpapi_ResolutionList_addAttribute(
        blpapi_ResolutionList_t *list, const blpapi_Name_t *name);

BLPAPI_EXPORT
int blpapi_ResolutionList_correlationIdAt(const blpapi_ResolutionList_t *list,
        blpapi_CorrelationId_t *result,
        size_t index);

BLPAPI_EXPORT
int blpapi_ResolutionList_topicString(const blpapi_ResolutionList_t *list,
        const char **topic,
        const blpapi_CorrelationId_t *id);

BLPAPI_EXPORT
int blpapi_ResolutionList_topicStringAt(
        const blpapi_ResolutionList_t *list, const char **topic, size_t index);

BLPAPI_EXPORT
int blpapi_ResolutionList_status(const blpapi_ResolutionList_t *list,
        int *status,
        const blpapi_CorrelationId_t *id);

BLPAPI_EXPORT
int blpapi_ResolutionList_statusAt(
        const blpapi_ResolutionList_t *list, int *status, size_t index);

BLPAPI_EXPORT
int blpapi_ResolutionList_attribute(const blpapi_ResolutionList_t *list,
        blpapi_Element_t **element,
        const blpapi_Name_t *attribute,
        const blpapi_CorrelationId_t *id);

BLPAPI_EXPORT
int blpapi_ResolutionList_attributeAt(const blpapi_ResolutionList_t *list,
        blpapi_Element_t **element,
        const blpapi_Name_t *attribute,
        size_t index);

BLPAPI_EXPORT
int blpapi_ResolutionList_message(const blpapi_ResolutionList_t *list,
        blpapi_Message_t **element,
        const blpapi_CorrelationId_t *id);

BLPAPI_EXPORT
int blpapi_ResolutionList_messageAt(const blpapi_ResolutionList_t *list,
        blpapi_Message_t **element,
        size_t index);

BLPAPI_EXPORT
int blpapi_ResolutionList_size(const blpapi_ResolutionList_t *list);

#ifdef __cplusplus
}

#ifndef INCLUDED_BLPAPI_EXCEPTION
#include <blpapi_exception.h>
#endif

namespace BloombergLP {
namespace blpapi {
// ====================
// class ResolutionList
// ====================

class ResolutionList {
    // Contains a list of topics that require resolution.
    //
    // Created from topic strings or from 'TopicSubscribed' messages
    // This is passed to a resolve() call or resolveAsync()
    // call on a 'ProviderSession'. It is updated and returned by the
    // resolve() call.

    blpapi_ResolutionList_t *d_handle_p;

  public:
    enum Status {
        UNRESOLVED = BLPAPI_RESOLUTIONLIST_UNRESOLVED,
        RESOLVED = BLPAPI_RESOLUTIONLIST_RESOLVED,
        RESOLUTION_FAILURE_BAD_SERVICE
        = BLPAPI_RESOLUTIONLIST_RESOLUTION_FAILURE_BAD_SERVICE,
        RESOLUTION_FAILURE_SERVICE_AUTHORIZATION_FAILED
        = BLPAPI_RESOLUTIONLIST_RESOLUTION_FAILURE_SERVICE_AUTHORIZATION_FAILED,
        RESOLUTION_FAILURE_BAD_TOPIC
        = BLPAPI_RESOLUTIONLIST_RESOLUTION_FAILURE_BAD_TOPIC,
        RESOLUTION_FAILURE_TOPIC_AUTHORIZATION_FAILED
        = BLPAPI_RESOLUTIONLIST_RESOLUTION_FAILURE_TOPIC_AUTHORIZATION_FAILED
    };

    // CLASS METHODS
    static Element extractAttributeFromResolutionSuccess(
            Message const& message, Name const& attribute);
    // !DEPRECATED!: Attributes are no longer supported.
    //
    // Return the value of the value in the specified 'message'
    // which represents the specified 'attribute'. The 'message'
    // must be a message of type "RESOLUTION_SUCCESS". The
    // 'attribute' should be an attribute that was requested using
    // addAttribute() on the ResolutionList passed to the
    // resolve() or resolveAsync() that caused this
    // RESOLUTION_SUCCESS message. If the 'attribute' is not
    // present an empty Element is returned.

    ResolutionList();
    // Create an empty ResolutionList.

    ResolutionList(const ResolutionList& original);
    // Copy constructor.

    virtual ~ResolutionList();
    // Destroy this ResolutionList.

    // MANIPULATORS

    virtual int add(const char *topic,
            const CorrelationId& correlationId = CorrelationId());
    // Add the specified 'topic' to this list, optionally
    // specifying a 'correlationId'. Returns 0 on success or
    // negative number on failure. After a successful call to
    // add() the status for this entry is UNRESOLVED_TOPIC.

    virtual int add(Message const& topicSubscribedMessage,
            const CorrelationId& correlationId = CorrelationId());
    // Add the topic contained in the specified
    // 'TopicSubscribed' message to this list, optionally
    // specifying a 'correlationId'.  Returns 0 on success or a
    // negative number on failure. After a successful call to add()
    // the status for this entry is UNRESOLVED_TOPIC.

    int addAttribute(const Name& attribute);
    // !DEPRECATED!: Attributes are no longer supported.
    //
    // Add the specified 'attribute' to the list of attributes
    // requested during resolution for each topic in this
    // ResolutionList. Returns 0 on success or a negative number
    // on failure.

    // ACCESSORS

    virtual CorrelationId correlationIdAt(size_t index) const;
    // Returns the CorrelationId of the specified 'index'th entry in
    // this ResolutionList. If 'index' >= size() an exception is
    // thrown.

    virtual const char *topicString(const CorrelationId& correlationId) const;
    // Returns a pointer to the topic of the entry identified by
    // the specified 'correlationId'. If the 'correlationId' does
    // not identify an entry in this ResolutionList then an
    // exception is thrown.

    virtual const char *topicStringAt(size_t index) const;
    // Returns a pointer to the topic of the specified 'index'th
    // entry. If 'index' >= size() an exception is thrown.

    virtual int status(const CorrelationId& correlationId) const;
    // Returns the status of the entry in this ResolutionList
    // identified by the specified 'correlationId'. This may be
    // UNRESOLVED, RESOLVED, RESOLUTION_FAILURE_BAD_SERVICE,
    // RESOLUTION_FAILURE_SERVICE_AUTHORIZATION_FAILED
    // RESOLUTION_FAILURE_BAD_TOPIC,
    // RESOLUTION_FAILURE_TOPIC_AUTHORIZATION_FAILED.  If the
    // 'correlationId' does not identify an entry in this
    // ResolutionList then an exception is thrown.

    virtual int statusAt(size_t index) const;
    // Returns the status of the specified 'index'th entry in this
    // ResolutionList. This may be UNRESOLVED,
    // RESOLVED, RESOLUTION_FAILURE_BAD_SERVICE,
    // RESOLUTION_FAILURE_SERVICE_AUTHORIZATION_FAILED
    // RESOLUTION_FAILURE_BAD_TOPIC,
    // RESOLUTION_FAILURE_TOPIC_AUTHORIZATION_FAILED.
    // If 'index' >= size() an exception is thrown.

    Element attribute(
            const Name& attribute, const CorrelationId& correlationId) const;
    // !DEPRECATED!: Attributes are no longer supported.
    //
    // Returns the value for the specified 'attribute' of the
    // entry in this ResolutionList identified by the specified
    // 'correlationId'. The Element returned may be empty if the
    // resolution service cannot provide the attribute. If
    // 'correlationId' does not identify an entry in this
    // ResolutionList or if the status of the entry identified by
    // 'correlationId' is not RESOLVED an exception is thrown.

    Element attributeAt(const Name& attribute, size_t index) const;
    // !DEPRECATED!: Attributes are no longer supported.
    //
    // Returns the value for the specified 'attribute' of the
    // specified 'index'th entry in this ResolutionList. The
    // Element returned may be empty if the resolution service
    // cannot provide the attribute. If 'index' >= size() or if
    // the status of the 'index'th entry is not RESOLVED an
    // exception is thrown.

    virtual Message const message(const CorrelationId& correlationId) const;
    // Returns the value of the message received during resolution
    // of the topic identified by the specified
    // 'correlationId'. If 'correlationId' does not identify an
    // entry in this ResolutionList or if the status of the entry
    // identify by 'correlationId' is not RESOLVED an exception is
    // thrown.
    //
    // The message returned can be used when creating an instance
    // of Topic.

    virtual Message const messageAt(size_t index) const;
    // Returns the value of the message received during resolution
    // of the specified 'index'th entry in this ResolutionList. If
    // 'index' >= size() or if the status of the 'index'th entry
    // is not RESOLVED an exception is thrown.
    //
    // The message returned can be used when creating an instance
    // of Topic.

    virtual size_t size() const;
    // Returns the number of entries in this list.

    const blpapi_ResolutionList_t *impl() const;

    blpapi_ResolutionList_t *impl();
};

// ============================================================================
//                      INLINE FUNCTION DEFINITIONS
// ============================================================================

// --------------------
// class ResolutionList
// --------------------

inline Element ResolutionList::extractAttributeFromResolutionSuccess(
        Message const&, Name const&)
{
    ExceptionUtil::throwOnError(BLPAPI_ERROR_UNSUPPORTED_OPERATION);

    // Unreachable code, previous statement throws.
    return Element();
}

inline ResolutionList::ResolutionList()
    : d_handle_p(blpapi_ResolutionList_create(0))
{
}

inline ResolutionList::ResolutionList(const ResolutionList& original)
    : d_handle_p(blpapi_ResolutionList_create(original.d_handle_p))
{
}

inline ResolutionList::~ResolutionList()
{
    blpapi_ResolutionList_destroy(d_handle_p);
}

inline int ResolutionList::add(
        const char *topic, const CorrelationId& correlationId)
{
    return blpapi_ResolutionList_add(d_handle_p, topic, &correlationId.impl());
}

inline int ResolutionList::add(Message const& topicSubscribedMessage,
        const CorrelationId& correlationId)
{
    return blpapi_ResolutionList_addFromMessage(
            d_handle_p, topicSubscribedMessage.impl(), &correlationId.impl());
}

inline int ResolutionList::addAttribute(const Name&)
{
    ExceptionUtil::throwOnError(BLPAPI_ERROR_UNSUPPORTED_OPERATION);

    // Unreachable code, previous statement throws.
    return BLPAPI_ERROR_UNSUPPORTED_OPERATION;
}

inline CorrelationId ResolutionList::correlationIdAt(size_t index) const
{
    blpapi_CorrelationId_t correlationId;
    ExceptionUtil::throwOnError(blpapi_ResolutionList_correlationIdAt(
            d_handle_p, &correlationId, index));

    return CorrelationId(correlationId);
}

inline const char *ResolutionList::topicString(
        const CorrelationId& correlationId) const
{
    const char *topic = 0;
    ExceptionUtil::throwOnError(blpapi_ResolutionList_topicString(
            d_handle_p, &topic, &correlationId.impl()));

    return topic;
}

inline const char *ResolutionList::topicStringAt(size_t index) const
{
    const char *topic = 0;
    ExceptionUtil::throwOnError(
            blpapi_ResolutionList_topicStringAt(d_handle_p, &topic, index));

    return topic;
}

inline int ResolutionList::status(const CorrelationId& correlationId) const
{
    int result = 0;
    ExceptionUtil::throwOnError(blpapi_ResolutionList_status(
            d_handle_p, &result, &correlationId.impl()));

    return result;
}

inline int ResolutionList::statusAt(size_t index) const
{
    int result = 0;
    ExceptionUtil::throwOnError(
            blpapi_ResolutionList_statusAt(d_handle_p, &result, index));

    return result;
}

inline Element ResolutionList::attribute(
        const Name&, const CorrelationId&) const
{
    ExceptionUtil::throwOnError(BLPAPI_ERROR_UNSUPPORTED_OPERATION);

    // Unreachable code, previous statement throws.
    return Element();
}

inline Element ResolutionList::attributeAt(const Name&, size_t) const
{
    ExceptionUtil::throwOnError(BLPAPI_ERROR_UNSUPPORTED_OPERATION);

    // Unreachable code, previous statement throws.
    return Element();
}

inline Message const ResolutionList::message(
        const CorrelationId& correlationId) const
{
    blpapi_Message_t *messageByCid = 0;
    ExceptionUtil::throwOnError(blpapi_ResolutionList_message(
            d_handle_p, &messageByCid, &correlationId.impl()));

    bool makeMessageCopyable = true;
    BLPAPI_CALL_MESSAGE_ADDREF(messageByCid);
    return Message(messageByCid, makeMessageCopyable);
}

inline Message const ResolutionList::messageAt(size_t index) const
{
    blpapi_Message_t *messageByIndex = 0;
    ExceptionUtil::throwOnError(blpapi_ResolutionList_messageAt(
            d_handle_p, &messageByIndex, index));

    bool makeMessageCopyable = true;
    BLPAPI_CALL_MESSAGE_ADDREF(messageByIndex);
    return Message(messageByIndex, makeMessageCopyable);
}

inline size_t ResolutionList::size() const
{
    return static_cast<size_t>(blpapi_ResolutionList_size(d_handle_p));
}

inline const blpapi_ResolutionList_t *ResolutionList::impl() const
{
    return d_handle_p;
}

inline blpapi_ResolutionList_t *ResolutionList::impl() { return d_handle_p; }

} // close namespace blpapi
} // close namespace BloombergLP

#endif // #ifdef __cplusplus
#endif // #ifndef INCLUDED_BLPAPI_RESOLUTIONLIST