/**
 * Ext.space.Fullscreen is an API for entering and leaving fullscreen mode.
 *
 * Sencha applications can make more screen space available by entering fullscreen
 * mode. Doing so is simple:
 *
 *      Ext.space.Fullscreen.enter().then(function() {
 *          // done entering fullscreen mode
 *      });
 *
 * Leaving fullscreen mode is similarly simple:
 *
 *      Ext.space.Fullscreen.leave().then(function() {
 *          // done leaving fullscreen mode
 *      });
 *
 * The Space Web Application Client allows the user to toggle fullscreen mode via
 * gesture input, so the Fullscreen module provides a hook you can use to add your
 * own listeners to the toggling process. Custom listeners fire on all fullscreen
 * toggle events, regardless of their source (gesture, `enter()`/`leave()`, etc...):
 *
 *      Ext.space.Fullscreen.onToggle(function(isFullscreen) {
 *          if (isFullscreen) {
 *              // something...
 *          } else {
 *              // another thing...
 *          }
 *      });
 *
 * Outside an `onToggle` handler, you can inspect the current fullscreen status with
 * a simple property check:
 *
 *      Ext.space.Fullscreen.ready().then(function() {
 *          if (Ext.space.Fullscreen.isEnabled) {
 *              // in fullscreen mode
 *          }
 *      });
 *
 * Note that the `isEnabled` property doesn't become reliable until shortly after the
 * main `Ext.onSpaceReady()` promise fulfills; the Fullscreen module uses its own
 * promise for notifying application code that it's ready to go, so if you need to
 * check the fullscreen status early in the application's lifecycle, you'll want to
 * wrap the check in a `ready()` handler, as above. In other cases, simply checking
 * the property directly works fine.
 *
 */
Ext.define("Ext.space.Fullscreen", {
    extend: Ext.space.Observable,
 
    singleton: true,
 
    /**
     * Whether or not fullscreen mode is currently enabled
     * @readonly
     * @type {boolean}
     */
    isEnabled: false,
 
    /**
     * @private
     */
    _ready: null,
 
    /**
     * @private
     */
    constructor: function() {
        Ext.onSpaceReady().then(function() {
            Ext.space.Fullscreen.superclass.constructor.apply(this, arguments);
            this.init();
        }.bind(this));
    },
 
    /**
     * @private
     */
    init: function() {
        var fullscreen = this;
 
        // check the mode we're starting in 
        var checkReady = new Ext.space.Promise();
        Ext.space.Communicator.send({
            command: "Fullscreen#isFullscreen",
            callbacks: {
                onSuccess: function(isFullscreen) {
                    fullscreen.isEnabled = isFullscreen;
                    checkReady.fulfill();
                },
                onError: function() {
                    // just assume we're not in fullscreen mode and carry on 
                    fullscreen.isEnabled = false;
                    checkReady.fulfill();
                }
            }
        });
 
        // listen for externally generated fullscreen togglings 
        var handlerReady = new Ext.space.Promise();
        Ext.space.Communicator.send({
            command: "Fullscreen#registerHandler",
            callbacks: {
                onToggle: this._onToggle.bind(this),
                onSuccess: function() {
                    handlerReady.fulfill();
                }
            }
        });
 
        this._ready = Ext.space.Promise.when(checkReady, handlerReady);
 
        return this._ready;
    },
 
    /**
     * Callback that fires when the application changes to/from fullscreen mode
     *
     * @private
     * @param {boolean} isFullscreen true if the application is now in fullscreen mode; false if not
     */
    _onToggle: function(isFullscreen) {
        this.isEnabled = isFullscreen;
        this.invokeListeners(isFullscreen);
    },
 
    /**
     * Check to see if the Fullscreen module is ready for use.
     *
     * @return {Ext.space.Promise} Promise that resolves when the module is ready.
     */
    ready: function() {
        return this._ready;
    },
 
    /**
     * Enter fullscreen mode
     *
     *      Ext.space.Fullscreen.enter().then(function(){
     *          // do something
     *      });
     *
     * @return {Ext.space.Promise} Promise that resolves when the application has entered fullscreen mode
     *
     */
    enter: function() {
        var result = new Ext.space.Promise();
 
        if (this._ready != null) {
            this._ready.then(function() {
                Ext.space.Communicator.send({
                    command: "Fullscreen#enter",
                    callbacks: {
                        onSuccess: function() {
                            result.fulfill();
                        },
                        onError: function(error) {
                            result.reject("Error entering fullscreen mode");
                        }
                    }
                });
            });
        }
 
        return result;
    },
 
    /**
     * Leave fullscreen mode
     *
     *      Ext.space.Fullscreen.leave().then(function(){
     *          // do something
     *      });
     *
     * @return {Ext.space.Promise} Promise that resolves when the application has left fullscreen mode
     *
     */
    leave: function() {
        var result = new Ext.space.Promise();
 
        if (this._ready != null) {
            this._ready.then(function() {
                Ext.space.Communicator.send({
                    command: "Fullscreen#leave",
                    callbacks: {
                        onSuccess: function() {
                            result.fulfill();
                        },
                        onError: function(error) {
                            result.reject("Error leaving fullscreen mode");
                        }
                    }
                });
            });
        }
 
        return result;
    },
 
    /**
     * Register a callback to run when the application changes into and out of
     * fullscreen mode.
     *
     * The callback will be passed a single parameter, a boolean value indicating
     * whether or not fullscreen mode is currently active (the callback runs after
     * the mode change is finished, so e.g., a value of `true` indicates that the
     * application has switched into fullscreen mode).
     *
     *      function switcheroo(isFullscreen) {
     *          Ext.space.Logger.log("Fullscreen switched; now " + (isFullscreen ? "on" : "off"));
     *      }
     *
     *      Ext.space.Fullscreen.onToggle(switcheroo);
     *      Ext.space.Fullscreen.enter(); // logs "Fullscreen switched; now on"
     *      Ext.space.Fullscreen.leave(); // logs "Fullscreen switched; now off"
     *
     *
     * @param {Function} callback Callback to fire when the application changes to or
     *                            from fullscreen mode.
     */
    onToggle: function(callback) {
        this.addListener.apply(this, arguments);
    }
});