/**
 * ## Examples
 *
 * To show a simple notification:
 *
 *     Ext.space.Notification.show({
 *         title: 'Verification',
 *         message: 'Is your email address: [email protected]',
 *         buttons: ['OK', 'Cancel'],
 *         callback: function(button) {
 *             if (button === 'OK') {
 *                 Ext.space.Logger.log('Verified');
 *             } else {
 *                 Ext.space.Logger.log('Nope');
 *             }
 *         }
 *     });
 *
 * To make the device vibrate:
 *
 *     Ext.space.Notification.vibrate();
 *
 * @mixins Ext.space.notification.Abstract
 *
 * @aside guide native_apis
 */
Ext.define('Ext.space.Notification', {
    singleton: true,
 
    /**
     * @private
     */
    events: null,
 
    /**
     * @private
     */
    _listeningForNotifications: false,
 
 
    /**
     * @private
     */
    constructor: function() {
        this.events = {
            badge: new Ext.space.Observable(),
            alert: new Ext.space.Observable(),
            data: new Ext.space.Observable()
        };
    },
 
    /**
     * Start listening for push notifications
     *
     * @private
     */
    _listenForNotifications: function() {
        this._listeningForNotifications = true;
        Ext.onSpaceReady().then(function() {
            Ext.space.Communicator.send({
                command: "Notification#registerHandler",
                callbacks: {
                    onApplicationBadgeChange: this._onBadgeChange.bind(this),
                    onApplicationAlertReceived: this._onAlert.bind(this),
                    onApplicationDataReceived: this._onData.bind(this),
                    onSuccess: function() { /* no need to do anything */ }
                }
            });
        }.bind(this));
    },
 
    show: function(config) {
        Ext.space.Communicator.send({
            command: 'Notification#show',
            callbacks: {
                callback: config.callback
            },
            scope  : config.scope,
            title  : config.title,
            message: config.message,
            buttons: config.buttons.join(',') //@todo fix this 
        });
    },
 
    vibrate: function() {
        Ext.space.Communicator.send({
            command: 'Notification#vibrate'
        });
    },
 
    /**
     * Gets the current badge value for the application.
     *
     * @return {Ext.space.Promise} Promise that resolves with the badge value
     */
    getBadge: function() {
        var result = new Ext.space.Promise();
 
        Ext.space.Communicator.send({
            command: "Notification#getCurrentBadge",
            callbacks: {
                onSuccess: function(badge) {
                    result.fulfill(badge);
                },
                onError: function(error) {
                    result.reject(error);
                }
            }
        });
 
        return result;
    },
 
    /**
     * Sets the badge value for the application.
     *
     * @param {string} badge badge value; null or empty string will clear the badge.
     * @return {Ext.space.Promise} Promise that resolves when the badge value is set.
     */
    setBadge: function(badge) {
        var result = new Ext.space.Promise();
 
        Ext.space.Communicator.send({
            command: "Notification#setCurrentBadge",
            badge: badge,
            callbacks: {
                onSuccess: function() {
                    result.fulfill();
                },
                onError: function(error) {
                    result.reject(error);
                }
            }
        });
 
        return result;
    },
 
    /**
     * Clears the current badge for the application.
     *
     * @return {Ext.space.Promise} Promise that resolves when the badge value is cleared.
     */
    clearBadge: function() {
        return this.setBadge("");
    },
 
    /**
     * Show an alert, similar to an alert from a push notification.
     *
     * @param {Object} config config object for the alert
     *                      message {string} - alert message
     *                      icon {string} - an optional url for the alert
     *                      tags {array} - array of tag strings
     * @return {Ext.space.Promise} Promise that resolves when the alert is shown.
     */
    showAlert: function(config) {
        var result = new Ext.space.Promise();
 
        Ext.space.Communicator.send({
            command: "Notification#showAlert",
            message: config.message,
            tags: config.tags,
            icon: config.icon,
            callbacks: {
                onSuccess: function() {
                    result.fulfill();
                },
                onError: function(error) {
                    result.reject(error);
                }
            }
        });
 
        return result;
    },
 
    /**
     * Get the application's notification settings.
     *
     * sendPushNotifications {boolean}            - if push notifications will be forwarded from the server
     * clientPushNotificationSettings {boolean}   - if the user can opt in/out of push notifications
     * userAlerts {boolean}                       - if the user has enabled alerts
     * userBadges {boolean}                       - if the user has enabled badges
     */
    getNotificationSettings: function() {
        var result = new Ext.space.Promise();
 
        Ext.space.Communicator.send({
            command: "Notification#getNotificationSettings",
            callbacks: {
                onSuccess: function(settings) {
                    result.fulfill(settings);
                },
                onError: function(error) {
                    result.reject(error);
                }
            }
        });
 
        return result;
    },
 
    /**
     * Callback that fires when the application's badge has changed.
     *
     * @private
     * @param {string} badgeValue the new badge's value.
     */
    _onBadgeChange: function(badgeValue) {
        this.events.badge.invokeListeners(badgeValue);
    },
 
    /**
     * Register a callback to run when the application's badge has changed.
     *
     *      function onBadgeChanged(badge) {
     *          Ext.space.Logger.log("New Badge: " + badge);
     *      }
     *
     *      Ext.space.Notification.onBadgeChange(onBadgeChanged);
     *
     * @param {Function} callback Callback for when the application's badge has changed.
     */
    onBadgeChange: function(callback) {
        if (!this._listeningForNotifications) {
            this._listenForNotifications();
        }
        this.events.badge.addListener(callback);
    },
 
    /**
     * Callback that fires when an alert is received.
     *
     * @private
     * @param {Object} alert the alert object.
     */
    _onAlert: function(alert) {
        this.events.alert.invokeListeners(alert);
    },
 
    /**
     * Register a callback to run when an alert is received.
     *
     *      function onAlertReceived(alert) {
     *          Ext.space.Logger.log("New alert: " + alert.message);
     *          // alert.icon string of the icon
     *          // alert.tags contains an array of tags
     *      }
     *
     *      Ext.space.Notification.onAlert(onAlertReceived);
     *
     * @param {Function} callback Callback for when an alert is received.
     */
    onAlert: function(callback) {
        if (!this._listeningForNotifications) {
            this._listenForNotifications();
        }
        this.events.alert.addListener(callback);
    },
 
    /**
     * Callback that fires when data is received.
     *
     * @private
     * @param {String} data the data string.
     */
    _onData: function(data) {
        this.events.data.invokeListeners(data);
    },
 
    /**
     * Register a callback to run when data is received.
     *
     *      function onDataReceived(data) {
     *          Ext.space.Logger.log("Data: " + data);
     *      }
     *
     *      Ext.space.Notification.onData(onDataReceived);
     *
     * @param {Function} callback Callback for when data is received.
     */
    onData: function(callback) {
        if (!this._listeningForNotifications) {
            this._listenForNotifications();
        }
        this.events.data.addListener(callback);
    }
});