text: /**
   * This class is used to write {@link Ext.data.Model} data to the server in a JSON format.
   * The {@link #allowSingle} configuration can be set to false to force the records to always
   * be encoded in an array, even if there is only a single record being sent.
   */
  Ext.define('Ext.data.writer.Json', {
      extend: 'Ext.data.writer.Writer',
      alternateClassName: 'Ext.data.JsonWriter',
      alias: 'writer.json',
      
      config: {
          /**
          * @cfg {String} rootProperty The HTTP parameter name by which JSON encoded records will be passed to the server if the
          * {@link #encode} option is `true`.
          */
          rootProperty: undefined,
      
          /**
          * @cfg {Boolean} [encode=false] Configure `true` to send record data (all record fields if {@link #writeAllFields} is `true`)
          * as a JSON encoded HTTP parameter named by the {@link #rootProperty} configuration.
          * 
          * The encode option should only be set to true when a {@link #rootProperty} is defined, because the values will be
          * sent as part of the request parameters as opposed to a raw post. The root will be the name of the parameter
          * sent to the server.
          */
          encode: false,
      
          /**
          * @cfg {Boolean} [allowSingle=true] Configure with `false` to ensure that records are always wrapped in an array, even if there is only
          * one record being sent. When there is more than one record, they will always be encoded into an array.
          */
          allowSingle: true,
      
          /**
          * @cfg {Boolean} [expandData=false] By default, when dot-delimited field {@link #nameProperty mappings} are
          * used (e.g. `name: 'myProperty', mapping: 'my.nested.property'`) the writer will simply output a flat data
          * object containing the mapping string literal as the property name (e.g. `{ 'my.nested.property': 'foo' }`).
          * 
          * Mappings are used to map incoming nested JSON to flat Ext models. In many case, the data output by the
          * writer should preferrably match the original nested data format. Setting this config to `true` will ensure
          * that the output will instead look like `{ my: { nested: { property: 'foo' }}}`. The output is generated
          * by {@link #getExpandedData}, which can optionally be overridden to apply more customized logic.
          */
          expandData: false
      },
      
      //<debug>
      constructor: function(config) {
          if (config && config.hasOwnProperty('root')) {
              config = Ext.apply({}, config);
              config.rootProperty = config.root;
              delete config.root;
              Ext.log.warn('Ext.data.writer.Json: Using the deprecated "root" configuration. Use "rootProperty" instead.');
          }
          this.callParent([config]);
      },
      //</debug>
      
      /**
       * @protected
       * The Reader classes support dot-delimited data mappings for extracting nested raw data into fields, so the
       * writer must support converting the flat {@link Ext.data.Model} structure back into the original nested data
       * format. Using the same mappings when available, the Writer will simply split each delimiter into a nested
       * object in the output, which should exactly match the input format. For example, record data like this:
       * 
       *     my.nested.property: 'foo',
       *     my.nested.another: 'bar',
       *     my.somethingElse: 123
       * 
       * should write out as...
       * 
       *     my: {
       *         nested: {
       *             property: 'foo',
       *             another: 'bar
       *         },
       *         somethingElse: 123
       *     }
       *
       * This behavior is governed by the {@link #expandData} config. By default, this option is `false` for
       * compatibility reasons, and will output a flat structure matching the flat record format. Setting this config
       * to `true` will enable the expanded mapping behavior as shown here. This method could also be overridden
       * to provide an even more customized output data structure.
       */
      getExpandedData: function(data) {
          var dataLength = data.length,
              i = 0,
              item,
              prop,
              nameParts,
              j,
              tempObj,
              
              toObject = function(name, value) {
                  var o = {};
                  o[name] = value;
                  return o;
              };
          
          for (; i < dataLength; i++) {
              item = data[i];
              
              for (prop in item) {
                  if (item.hasOwnProperty(prop)) {
                      // e.g. my.nested.property: 'foo'
                      nameParts = prop.split('.');
                      j = nameParts.length - 1;
                      
                      if (j > 0) {
                          // Initially this will be the value 'foo'.
                          // Equivalent to rec['my.nested.property']
                          tempObj = item[prop];
                          
                          for (; j > 0; j--) {
                              // Starting with the value above, we loop inside out, assigning the
                              // current object as the value for the parent name. Work all
                              // the way up until only the root name is left to assign.
                              tempObj = toObject(nameParts[j], tempObj);
                          }
                          
                          // At this point we'll have all child properties rolled up into a single
                          // object like `{ nested: { property: 'foo' }}`. Now add the root name
                          // (e.g. 'my') to the record data if needed (do not overwrite existing):
                          item[nameParts[0]] = item[nameParts[0]] || {};
                          // Since there could be duplicate names at any level of the nesting be sure
                          // to merge rather than assign when setting the object as the value:
                          Ext.Object.merge(item[nameParts[0]], tempObj);
                          // Finally delete the original mapped property from the record
                          delete item[prop];
                      }
                  }
              }
          }
          return data;
      },
      
      writeRecords: function(request, data) {
          var me = this,
              root = me.getRootProperty(),
              json, single, transform;
          
          if (me.getExpandData()) {
              data = me.getExpandedData(data);
          }
          
          if (me.getAllowSingle() && data.length === 1) {
              // convert to single object format
              data = data[0];
              single = true;
          }
          
          transform = this.getTransform();
          if (transform) {
              data = transform(data, request);
          }
          
          if (me.getEncode()) {
              if (root) {
                  // sending as a param, need to encode
                  request.setParam(root, Ext.encode(data));
              } else {
                  //<debug>
                  Ext.raise('Must specify a root when using encode');
                  //</debug>
              }
          } else if (single || (data && data.length)) {
              // send as jsonData
              json = request.getJsonData() || {};
              if (root) {
                  json[root] = data;
              } else {
                  json = data;
              }
              request.setJsonData(json);
          }
          return request;
      }
  });
  