//
//  NotificationCenter.h
//  Meteor
//
//  Created by Cesar Parent on 13/08/2015.
//  Copyright (c) 2015 Cesar Parent. All rights reserved.
//

#ifndef __Meteor__NotificationCenter__
#define __Meteor__NotificationCenter__

#include "../defines.h"
#include "../CPFoundation.h"
#include <vector>
#include <string>
#include <functional>

NS_BEGIN

/*
 * @defgroup        Notification Notification Types
 * @brief           List of existing notification types
 */


/*!
 * @class           Notification
 * @ingroup         Foundation Management
 * @brief           A notification object carries a name, and optionally an CPObject subclass object
 *                  broadcast to appropriate receivers.
 */
struct Notification {
    /*!
     * @internal
     * @brief       
     */
    Notification(const char* name, CPObject* object);
    
    /*!
     * @internal
     * @brief       Notification destructor. releases the object if it isn't null.
     */
    virtual ~Notification();
    
    /*!
     * @brief       The notification's name.
     */
    const char* name;
    /*!
     * @brief       The object that sent the notification, or arbitrary data
     */
    const CPObject* object;
};

struct NotificationObserver;

/*!
 * @class           NotificationCenter
 * @ingroup         Foundation Management
 * @brief           A class that provides a mechanism for broadcasting information within a program.
 * @details         Functions can be registered with the Notification Center to receive
 *                  notifications (Notification objects) using addObserver(). A method can be
 *                  registered multiple times, and can thus receive multiple types of notifications.
 *
 *                  NotificationCenter provides a static API: you don't need to create a new
 *                  notification center to use it.
 */
class NotificationCenter final {
public:
    
    /**
     * @name        Registering Observers
     * @{
     */
    
    /*!
     * @brief       Registers an observer function for a notification type and sender.
     *              If <code>name</code> is <code>nullptr</code>, then all notifications with a
                    matching <code>object</code> will be forwarded to <code>observer</code>. If
     *              <code>object</code> is <code>null</code>, all notifications with a matching name
     *              will be. If both conditions are true, then every notification will be forwarded.
     * @param       name        Name of the notifications the observer wants to receive.
     * @param       object      Sender of the notifications the observer wants to receive.
     * @param       observer    The observer function that will be called when a notification is
     *                          posted.
     */
    static void
    addObserver(const char* name,
                CPObject* object,
                std::function<void(const Notification&)> observer);
    
    /**
     * @}
     * @name        Removing Observers
     * @{
     */
    
    /*!
     * @brief       Removes observers for the matching name and object. Any object that will be
     *              deleted should remove itself from the notification center's dispatch list.
     * @param       name        Notification name of the observer to remove.
     * @param       object      Notification object of the observer to remove.
     */
    static void
    removeObserver(const char* name, CPObject* object);
    
    /**
     * @}
     * @name        Posting Notifications
     * @{
     */
    
    /*!
     * @brief       Posts a notification to matchin observers.
     * @param       name        Notification's name.
     * @param       object      The object to attach to the notification. This is usually the object
     *                          sending the notification.
     */
    static void
    postNotification(const char* name, CPObject* object);
    
    /**
     * @}
     */
    
    
private:
    
    static bool
    observerExists(const char* name, CPObject* object);
    
    static
    std::vector<NotificationObserver> _observers;
};



NS_END

#endif /* defined(__Meteor__NotificationCenter__) */
