text: /**
   * @author Don Griffin
   *
   * This singleton manages simulated Ajax responses. This allows application logic to be
   * written unaware that its Ajax calls are being handled by simulations ("simlets"). This
   * is currently done by hooking {@link Ext.data.Connection} methods, so all users of that
   * class (and {@link Ext.Ajax} since it is a derived class) qualify for simulation.
   *
   * The requires hooks are inserted when either the {@link #init} method is called or the
   * first {@link Ext.ux.ajax.Simlet} is registered. For example:
   *
   *      Ext.onReady(function () {
   *          initAjaxSim();
   *
   *          // normal stuff
   *      });
   *
   *      function initAjaxSim () {
   *          Ext.ux.ajax.SimManager.init({
   *              delay: 300
   *          }).register({
   *              '/app/data/url': {
   *                  stype: 'json',  // use JsonSimlet (stype is like xtype for components)
   *                  data: [
   *                      { foo: 42, bar: 'abc' },
   *                      ...
   *                  ]
   *              }
   *          });
   *      }
   *
   * As many URL's as desired can be registered and associated with a {@link Ext.ux.ajax.Simlet}. To make
   * non-simulated Ajax requests once this singleton is initialized, add a `nosim:true` option
   * to the Ajax options:
   *
   *      Ext.Ajax.request({
   *          url: 'page.php',
   *          nosim: true, // ignored by normal Ajax request
   *          params: {
   *              id: 1
   *          },
   *          success: function(response){
   *              var text = response.responseText;
   *              // process server response here
   *          }
   *      });
   */
  Ext.define('Ext.ux.ajax.SimManager', {
      singleton: true,
  
      requires: [
          'Ext.data.Connection',
          'Ext.ux.ajax.SimXhr',
          'Ext.ux.ajax.Simlet',
          'Ext.ux.ajax.JsonSimlet'
      ],
  
      /**
       * @cfg {Ext.ux.ajax.Simlet} defaultSimlet
       * The {@link Ext.ux.ajax.Simlet} instance to use for non-matching URL's. By default, this will
       * return 404. Set this to null to use real Ajax calls for non-matching URL's.
       */
  
      /**
       * @cfg {String} defaultType
       * The default `stype` to apply to generic {@link Ext.ux.ajax.Simlet} configuration objects. The
       * default is 'basic'.
       */
      defaultType: 'basic',
  
      /**
       * @cfg {Number} delay
       * The number of milliseconds to delay before delivering a response to an async request.
       */
      delay: 150,
  
      /**
       * @property {Boolean} ready
       * True once this singleton has initialized and applied its Ajax hooks.
       * @private
       */
      ready: false,
  
      constructor: function () {
          this.simlets = {};
      },
  
      getSimlet: function (url) {
          // Strip down to base URL (no query parameters or hash):
          var me = this,
              index = url.indexOf('?');
  
          if (index < 0) {
              index = url.indexOf('#');
          }
          if (index > 0) {
              url = url.substring(0, index);
          }
  
          return me.simlets[url] || me.defaultSimlet;
      },
  
      getXhr: function (method, url, options, async) {
          var simlet = this.getSimlet(url);
  
          if (simlet) {
              return simlet.openRequest(method, url, options, async);
          }
  
          return null;
      },
  
      /**
       * Initializes this singleton and applies configuration options.
       * @param {Object} config An optional object with configuration properties to apply.
       * @return {Ext.ux.ajax.SimManager} this
       */
      init: function (config) {
          var me = this;
  
          Ext.apply(me, config);
  
          if (!me.ready) {
              me.ready = true;
  
              if (!('defaultSimlet' in me)) {
                  me.defaultSimlet = new Ext.ux.ajax.Simlet({
                      status: 404,
                      statusText: 'Not Found'
                  });
              }
  
              me._openRequest = Ext.data.Connection.prototype.openRequest;
  
              Ext.data.Connection.override({
                  openRequest: function (options, requestOptions, async) {
                      var xhr = !options.nosim &&
                                me.getXhr(requestOptions.method, requestOptions.url, options, async);
                      if (!xhr) {
                          xhr = this.callParent(arguments);
                      }
                      return xhr;
                  }
              });
  
              if (Ext.data.JsonP) {
                  Ext.data.JsonP.self.override({
                      createScript: function (url, params, options) {
                          var fullUrl = Ext.urlAppend(url, Ext.Object.toQueryString(params)),
                              script = !options.nosim &&
                                       me.getXhr('GET', fullUrl, options, true);
  
                          if (!script) {
                              script = this.callParent(arguments);
                          }
  
                          return script;
                      },
  
                      loadScript: function (request) {
                          var script = request.script;
                          if (script.simlet) {
                              script.jsonpCallback = request.params[request.callbackKey];
                              script.send(null);
                          } else {
                              this.callParent(arguments);
                          }
                      }
                  });
              }
          }
  
          return me;
      },
  
      openRequest: function (method, url, async) {
          var opt = {
              method: method,
              url: url
          };
          return this._openRequest.call(Ext.data.Connection.prototype, {}, opt, async);
      },
  
      /**
       * Registers one or more {@link Ext.ux.ajax.Simlet} instances.
       * @param {Array/Object} simlet Either a {@link Ext.ux.ajax.Simlet} instance or config, an Array
       * of such elements or an Object keyed by URL with values that are {@link Ext.ux.ajax.Simlet}
       * instances or configs.
       */
      register: function (simlet) {
          var me = this;
  
          me.init();
  
          function reg (one) {
              var simlet = one;
              if (!simlet.isSimlet) {
                  simlet = Ext.create('simlet.' + (simlet.stype || me.defaultType), one);
              }
              me.simlets[one.url] = simlet;
              simlet.manager = me;
          }
  
          if (Ext.isArray(simlet)) {
              Ext.each(simlet, reg);
          } else if (simlet.isSimlet || simlet.url) {
              reg(simlet);
          } else {
              Ext.Object.each(simlet, function (url, s) {
                  s.url = url;
                  reg(s);
              });
          }
  
          return me;
      }
  });
  